راهنمای شروع کار با جنگو

ورژن 2.2

ترجمه‌ای آزاد همراه با کمی توضیحات بیشتر از سایت رسمی پروژه جنگو

جنگو در یک نگاه

جنگو با فلسفه توسعه سریع و راحت، ایجاد شده. در این بخش شما خیلی سریع از نظر تکنیکی می‌فهمید که جنگو چطور کار می‌کنه. این بخش برای آموزش طراحی نشده. اگر چیزی ازش نمی‌فهمید یا به نظرتون خیلی گیج‌کننده و درهم برهم میاد، نگران نباشید، ما یک آموزش جالب و جذاب هم داریم. هر وقت آماده بودید تا یک پروژه واقعی جنگو رو شروع کنید، می‌تونید از شروع آموزش دیدن کنید!

به طور کلی جنگو از سه بخش تشکیل شده: مدل داده، توابع ویو و قالب‌ها. شما نحوه مدل‌بندی داده‌هاتون رو با استفاده از کلاس‌های پایتون طراحی می‌کنید، بعد جنگو خودش اون‌ها رو در دیتابیس ایجاد می‌کنه. حالا یک قالب برای یکی از صفحات‌تون طراحی می‌کنید، برای اون یک تابع ویو می‌نویسید که مشخص می‌کنه زمانی که کاربر می‌خواد اون صفحه رو ببینه، باید چه اتفاقی رخ بده؛ بعد یک الگو آدرس (URL Pattern) تعریف می‌کنید که مشخص می‌کنه چه آدرسی در سایت به چه ویویی ارسال بشه.

مدل‌تون رو طراحی کنید

گرچه شما می‌تونید از جنگو، بدون دیتابیس هم استفاده کنید، اما جنگو با یک ORM یا object-relational mapper که یک روش مدرن در مدیریت اطلاعات هست همراه شده. به این صورت که شما می‌تونید مدل پایه دیتابیس‌تون رو با استفاده از کدهای پایتون پیاده‌سازی کنید.

سینتکس منحصر به فرد مدل‌های جنگو یک عالم راه‌های خوب برای شبیه‌سازی و پیاده کردن مدل‌های مدیریت اطلاعات‌تون ارائه می‌ده. خب این باعث شده که یک‌سری از مشکلات چندین ساله دیتابیس حل بشه. یک مثال سریع ببینید:

mysite/news/models.py:

	from django.db import models
	class Reporter(models.Model):
	    full_name = models.CharField(max_length=70)

	    def __str__(self):
		return self.full_name

	class Article(models.Model):
	    pub_date = models.DateField()
	    headline = models.CharField(max_length=200)
	    content = models.TextField()
	    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

	    def __str__(self):
		return self.headline

نصب‌ش کنید

بعد از این‌که مدل‌تون پیاده‌سازی شد، این دستورات رو در ترمینال وارد کنید.


$ python manage.py makemigrations
$ python manage.py migrate

دستور makemigrations همه‌ی مدل‌هایی که پیاده‌سازی کردید رو نگاه می‌کنه و یک migrations از اون‌ها برای جداولی که از قبل وجود نداشتن می‌سازه. پس از اون دستور migrate می‌آد و migrationsهای ساخته شده رو اجرا می‌کنه و جداول مورد نیاز در دیتابیس شما ساخته می‌شه.


از APIهای آزاد استفاده و کِیف کنید!

شما با استفاده از Python API که آزاد و خیلی هم خفن هست به دیتاهاتون دسترسی دارید. این APIها در آسمان‌ها ساخته شدن؛ یعنی نیاز به تولید هیچ کدی نیست:

# Import the models we created from our "news" app
>>> from news.models import Article, Reporter

# No reporters are in the system yet.
>>> Reporter.objects.all()
<QuerySet []>

# Create a new Reporter.
>>> r = Reporter(full_name='John Smith')

# Save the object into the database. You have to call save() explicitly.
>>> r.save()

# Now it has an ID.
>>> r.id
1

# Now the new reporter is in the database.
>>> Reporter.objects.all()
<QuerySet [<Reporter: John Smith>]>

# Fields are represented as attributes on the Python object.
>>> r.full_name
'John Smith'

# Django provides a rich database lookup API.
>>> Reporter.objects.get(id=1)
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__startswith='John')
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__contains='mith')
<Reporter: John Smith>
>>> Reporter.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Reporter matching query does not exist.

# Create an article.
>>> from datetime import date
>>> a = Article(pub_date=date.today(), headline='Django is cool',
...     content='Yeah.', reporter=r)
>>> a.save()

# Now the article is in the database.
>>> Article.objects.all()
<QuerySet [<Article: Django is cool>]>

# Article objects get API access to related Reporter objects.
>>> r = a.reporter
>>> r.full_name
'John Smith'

# And vice versa: Reporter objects get API access to Article objects.
>>> r.article_set.all()
<QuerySet [<Article: Django is cool>]>

# The API follows relationships as far as you need, performing efficient
# JOINs for you behind the scenes.
# This finds all articles by a reporter whose name starts with "John".
>>> Article.objects.filter(reporter__full_name__startswith='John')
<QuerySet [<Article: Django is cool>]>

# Change an object by altering its attributes and calling save().
>>> r.full_name = 'Billy Goat'
>>> r.save()

# Delete an object with delete().
>>> r.delete()

یک رابط مدیریت پویا: این یک اسکلت خالی نیست، کل ساختمونه!

وقتی که مدل شما پیاده‌سازی شد، جنگو می‌تونه به صورت اتوماتیک یک رابط مدیریتی حرفه‌ای، قابل استفاده و خوانا بسازه. در وبسایت، کاربران می‌تونن اشیا جدید بسازند، اون‌ها رو ویرایش کنند یا حذف‌شون کنند. این کار به سادگی با ثبت کردن مدل‌تون در بخش ادمین امکان پذیره:

mysite/news/models.py:

from django.db import models

class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

mysite/news/admin.py:

from django.contrib import admin
from . import models

admin.site.register(models.Article)

فلسفه کار اینه که سایت شما توسط همکاران شما، کاربران شما یا فقط خودتون ویرایش می‌شه - همچنین شما نمی‌خواید که با مشکلات زیاد ایجاد یک رابط پشتی برای مدیریت محتوا سایت‌تون دست و پنجه نرم کنید.

یک روش کار معمول در ساخت پروژه‌های جنگو اینه‌که شما مدل‌هاتون رو می‌سازید و بخش ادمین سایت‌تون رو هرچه زودتر راه‌اندازی می‌کنید؛ حالا همکاران یا کاربران شما می‌تونن دیتاهایی رو در سایت وارد کنند. بعد از اون یک راهی رو طراحی می‌کنید که اون اطلاعات به صورت عمومی منتشر و استفاده بشه.


آدرس‌هاتون رو طراحی کنید

یک الگو آدرس تمیز و زیبا، جزئی مهم از یک وب‌اپلیکیشن سطح بالاست. جنگو شما رو ترغیب می‌کنه به طراحی آدرس‌های زیبا و چیزهای بیهوده‌ای مثل .php یا .asp در اون‌ها قرار نمی‌ده.

برای طراحی آدرس‌های یک اپ، یک ماژول پایتون می‌سازید به نام URLconf. یعنی یک فهرست محتوا از اپ‌تون؛ که یک رابط ساده بین الگوهای آدرس و توابع پایتون هست. URLconfها همچنین برای جدا کردن آدرس‌ها از کد پایتون هم استفاده می‌شن.

کد زیر یک مثال از URLconf یک سایت خبری است.

mysite/news/urls.py:

from django.urls import path

from . import views

urlpatterns = [
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<int:pk>/', views.article_detail),
]

کد بالا یک رابط بین آدرس‌های اینترنتی و توابع کال‌بک پایتون (مترجم: ترجمه مناسبی برای کال‌بک پیدا نکردم!) یا اصطلاحا ویوها (views) هست. رشته‌های path از پارامترها استفاده می‌کنند تا اطلاعات رو از آدرس‌ها «استخراج» کنند. زمانی که کاربر برای دیدن یک صفحه درخواست به سرور ارسال می‌کنه، جنگو به ترتیب توی هر path حرکت می‌کنه و اگر یکی از مسیرها با آدرس درخواست شده مطابقت داشت، همون‌جا توقف می‌کنه. (اگر هیچ‌کدوم از مسیرها با آدرس درخواست شده مطابقت نداشت، جنگو ویو ۴۰۴ (404 view) رو فراخوانی می‌کنه.) جنگو این کار رو خیلی سریع انجام می‌ده.

زمانی که یکی از آدرس‌ها با آدرس درخواستی مطابقت داشت، جنگو ویو مربوط بهش که یک تابع پایتونی هست رو فراخوانی می‌کنه. هر ویو یک آبجکت request رو به عنوان ورودی دریافت می‌کنه - که شامل متادیتاهای درخواست (request) هست - و مقادیر موجود در الگوها استخراج می‌شه. برای مثال اگر کاربر درخواست آدرس “articles/2005/05/39323/” رو فراخوانی کرده باشه جنگو تابع زیر رو فراخوانی می‌کنه:

news.views.article_detail(request, year=2005, month=5, pk=39323).


ویوهاتون رو بنویسد

هر ویو مسئول انجام یکی از این دو کار هست: برگردوندن یک آبجکت HttpResponse که حاوی محتوای صفحه درخواست شده هست، یا بالا آوردن یک خطا مثل Http404. بقیه‌ش به عهده خودتون‌ـه.

به طور عمده، یک ویو، مقادیری رو از پارامترهای ورودی‌ش دریافت می‌کنه، یک قالب رو لود می‌کنه و قالب رو با مقادیر دریافت شده برای کاربر رندر می‌کنه. در زیر یک مثال از ویو آرشیو سالانه مقالات رو ببینیم.

mysite/news/views.py:

from django.shortcuts import render

from .models import Article

def year_archive(request, year):
    a_list = Article.objects.filter(pub_date__year=year)
    context = {'year': year, 'article_list': a_list}
    return render(request, 'news/year_archive.html', context)

مثال بالا از سیستم قالب جنگو استفاده کرده، که امکانات خیلی جالبی داره منتها سعی کرده که اون‌قدر ساده باشه که غیر برنامه‌نویس‌ها هم بتونن ازش استفاده کنن.


قالب‌هاتون رو طراحی کنید

کد بالا داره قالب news/year_archive.html رو لود می‌کنه.
حنگو یک جستجوگر آدرس قالب داره که کمک می‌کنه تا اضافه‌کاری‌های کار با قالب‌ها از بین برن. در بخش تنظیمات جنگو، شما با استفاده از دیکشنری DIRS یک لیست از پوشه‌هایی که باید برای قالب‌هاتون چک بشن رو مشخص می‌کنید. اگر قالب مورد نظر در پوشه اولی وجود نداشت، اون پوشه دوم رو چک می‌کنه و الی آخر.

بیاید تصور کنیم که قالب news/year_archive.html پیدا شد. در این صورت اون چیزی شبیه به کد زیر هست:

mysite/news/templates/news/year_archive.html:

{% extends "base.html" %}

{% block title %}Articles for {{ year }}{% endblock %}

{% block content %}
<h1>Articles for {{ year }}</h1>

{% for article in article_list %}
    <p>{{ article.headline }}</p>
    <p>By {{ article.reporter.full_name }}</p>
    <p>Published {{ article.pub_date|date:"F j, Y" }}</p>
{% endfor %}
{% endblock %}

متغیرها با براکت‌های دوگانه مشخص شدن. {{ article.headline }} یعنی: «مقدار موجود در ویژگی عنوان مقاله رو چاپ کن.» اما نقطه‌ها فقط برای پیدا کردن ویژگی‌ها استفاده نمی‌شن. اون‌ها برای جستجو در دیکشنری‌ها، ایندکس‌ها و فراخوانی توابع هم استفاده می‌شن.

به {{ article.pub_date|date:“F j, Y” }} توجه کنید. اون از مدل یونیکیسی «پایپ کردن» (استفاده از کاراکتر |) استفاده می‌کنه. این یک فیلتر قالب گفته می‌شه. این یک راه خوب برای فیلترگذاری در مقادیر متغیرهاست. مثلا در این مورد شئ تاریخ و زمان پایتون، فقط نوعی خاص از تاریخ رو دریافت می‌کنه. (مشابه چیزی که در تابع زمان PHP وجود داره.)

شما می‌تونید هر تعداد فیلتری که دوست دارید رو به صورت زنجیروار به هم وصل و استفاده کنید. شما می‌تونید فیلترهای قالب خودتون رو بنویسد. یا حتی می‌تونید تگ‌های قالب دل‌خواه‌تون رو بنویسید، که یک‌سری کدهای پایتون مورد نیازتون رو در پشت صحنه اجرا می‌کنن.

در نهایت در جنگو مفهومی به اسم «ارث‌بری قالب» وجود داره. {% extends “base.html” %} چیزی‌ـه که راجع بهش صحبت می‌کنیم. این یعنی «اول از همه قالبی به اسم base رو لود کن، که درش تعدادی بلوک تعریف شده. حالا بلوک‌ها رو با مقادیر دلخواه پر کن.» به طور خلاصه این باعث می‌شه که به شکل دراماتیکی دیگه اضافه‌کاری‌ای برای قالب‌ها نداشته باشید. در هر قالب فقط چیزهای یکتا تعریف می‌شه. تکراری‌ها فقط یک‌بار تعریف شدن و در هر قالب ارث‌بری می‌شن!

در زیر قالب “base.html” رو می‌بینید که از فایل‌های استاتیک هم استفاده کرده.

mysite/templates/base.html:

{% load static %}
<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <img src="{% static "images/sitelogo.png" %}" alt="Logo">
    {% block content %}{% endblock %}
</body>
</html>

به طور ساده، این یک تم اصلی برای سایت تعریف کرده (همراه با لوگو) و یک‌سری جاهای خالی برای قالب‌های فرزند تا پرشون کنن. این‌کار بازطراحی سایت رو به سادگی تغییر فقط یک فایل می‌کنه. قالب base.

این همچنین به شما این امکان رو می‌ده که چند ورژن مختلف از سایت رو بسازید، با قالب‌های پایه مختلف که درحال استفاده توسط قالب‌های فرزند هستن. جنگو کارها از این تکنیک برای ساخت ورژن‌های موبایل مختلف سایت - به سادگی ساخت یک قالب پایه جدید - استفاده می‌کنند.

همچنین این نکته جالب هست که شما مجبور نیستید از سیستم قالب جنگو استفاده کنید اگر سیستم دیگه‌ای رو ترجیح می‌دید. درحالی که سیستم قالب جنگو تطبیق‌پذیری خوبی با لایه مدل جنگو داره، اما شما اصلا مجبور به استفاده ازش نیستید. برای این مورد شما نباید از APIهای دیتابیس جنگو استفاده کنید. حتی شما می‌تونید از لایه‌های انتزاعی یک دیتابیس دیگه استفاده کنید. شما می‌تونید فایل‌های XML رو بخونید یا هر چیزی که بخواید. هر قسمت از جنگو - مدل‌های داده‌ای، ویوها و قالب‌ها - از هم دیگه جدا هستند.


این فقط سطح این دریا بود!

این فقط یک معرفی کلی و سریع از کارکرد جنگو بود. بعضی از امکانات دیگه جنگو:

  • یک فرم‌ورک کش کردن که با سایر بک‌اندها سازگار هست.
  • یک فریم‌ورک Syndication که به سادگی نوشتن یک کلاس پایتون، براتون فید RSS یا Atom تولید می‌کنه.
  • امکاناتی که بخش جنگو به صورت خودکار ایجاد می‌کنه بسیار جذاب‌تر از چیزی هست که این‌جا توضیح داده شد، این‌جا فقط چیزهای سطحی از اون رو بررسی کردیم.

قدم شگفت‌انگیز بعدی برای شما می‌تونه نصب جنگو یا خوندن آموزش باشه. ممنون به خاطر این‌که تا این‌جا قضیه اومدین و هنوز ناامید نشدین. تقریبا سخت‌ترین مرحله شروع آموزش رو رد کردیم. مرحله سردرگمی!