اولین پروژهای که در کتاب django by example با جنگو میسازید، یک blog application خواهد بود. این پروژه به شما کمک میکند تا با تواناییها و امکانات اصلی Django بهخوبی آشنا شوید.
وبلاگ، بهترین نقطهی شروع برای یادگیری Django است، چون امکانات متنوعی نیاز دارد؛ از مدیریت محتوای ساده گرفته تا قابلیتهای پیشرفته مثل commenting، post sharing، search و post recommendations. در سه فصل اول این کتاب، روی همین پروژه کار خواهیم کرد.
در این فصل، ابتدا یک Django project و یک Django application برای وبلاگ میسازیم. سپس data models را طراحی میکنیم و آنها را با database هماهنگ میکنیم. در ادامه، یک administration site برای وبلاگ راهاندازی میکنیم و بعد سراغ ساخت views، templates و URLs میرویم.
در عکس1.2 تصویری از صفحاتی که قرار است برای blog application بسازید، نشان داده شده است.
برنامه blog application شامل یک لیست از posts خواهد بود که در آن عنوان پست(post title), تاریخ انتشار(publishing date)، نویسنده (author)، یک post excerpt و لینکی برای خواندن پست نمایش داده میشود. صفحهی لیست پستها با استفاده از post_list view پیادهسازی خواهد شد. در این فصل یاد میگیرید که چگونه views ایجاد کنید.
وقتی خوانندگان روی لینک یک پست در صفحهی لیست پستها کلیک کنند، به یک single (detail) view از آن پست منتقل میشوند. در تاریخ انتشار و عنوان نویسنده و متن کامل پست نمایش داده خواهد شد.
بیایید با ایجاد یک Django project برای وبلاگ کار خود را آغاز کنیم. Django دستوری در اختیار شما قرار میدهد که به کمک آن میتوانید ساختار اولیه فایلهای پروژه را ایجاد کنید.
توجه داشته باشید قبل از اجرا کردن دستو زیر ،باید محیط مجازی (virtual enviroment ) را برای پروژه ی خود درست کرده باشید و سپس جنگو را نصب کنید .آموزش این قسمت را ، به صورت کامل در مقاله ی نصب جنگو در محیط مجازی گفته شده است.
حالا، این دستور را در shell prompt اجرا کنید:
django-admin startproject mysite
این دستور یک پروژه جنگو با نام mysite ایجاد خواهد کرد.
از نامگذاری پروژهها با نام Python modules یا Django modules داخلی خودداری کنید تا از ایجاد تداخل جلوگیری شود.
حال بیایید نگاهی به ساختار پروژهی ایجادشده بیندازیم:
mysite/
manage.py
mysite/
__init__.py
asgi.py
settings.py
urls.py
wsgi.py
پوشهی بیرونی mysite/ ظرف اصلی پروژهی ما است. این پوشه شامل فایلهای زیر میباشد:
manage.py: یک ابزار خط فرمان است که برای تعامل با پروژه استفاده میشود. معمولاً نیازی به ویرایش این فایل نخواهید داشت.
mysite/: این پوشه Python package پروژه است و شامل فایلهای زیر میباشد:
- __init__.py: یک فایل خالی که به Python اعلام میکند پوشهی mysite یک Python module است.
- asgi.py: تنظیمات اجرای پروژه به صورت یک ASGI application با وبسرورهای سازگار با ASGI. (ASGI استاندارد جدید Python برای وبسرورها و برنامههای asynchronous است.)
- settings.py: شامل تنظیمات و پیکربندیهای پروژه است و مقادیر پیشفرض اولیه را در خود دارد.
- urls.py: جایی است که URL patterns تعریف میشوند. هر URL در اینجا به یک view متصل میشود.
- wsgi.py: تنظیمات اجرای پروژه به صورت یک WSGI application با وبسرورهای سازگار با WSGI.
اعمال مایگریشنهای اولیه دیتابیس
برنامههای جنگو برای ذخیره دادهها به یک دیتابیس نیاز دارند. فایل settings.py شامل تنظیمات دیتابیس پروژه در بخش DATABASES است.که بهطور پیشفرض، یک دیتابیس SQLite3 تنظیم شده است.
SQLite همراه با Python 3 ارائه میشود و میتوان آن را در هر برنامهی Python استفاده کرد. این دیتابیس سبک است و میتوانید از آن برای توسعه پروژههای Django استفاده کنید. اما اگر قصد دارید برنامه را در یک محیط production اجرا کنید، بهتر است از یک دیتابیس کاملتر مثل PostgreSQL، MySQL یا Oracle استفاده کنید. اطلاعات بیشتر دربارهی راهاندازی دیتابیس با Django را میتوانید در این صفحه پیدا کنید
فایل settings.py همچنین لیستی به نام INSTALLED_APPS دارد که شامل چند برنامهی عمومی Django است که به صورت پیشفرض به پروژه اضافه میشوند. در بخش تنظیمات پروژه به این برنامهها بیشتر میپردازیم.
برنامههای جنگو شامل data models هستند که به جدول دیتابیس متصل میشوند. شما در بخش ساخت دیتامدل، مدلهای خود را ایجاد خواهید کرد. برای تکمیل راهاندازی پروژه، لازم است جداول مربوط به مدلهای برنامههای پیشفرض Django که در INSTALLED_APPS تعریف شدهاند ایجاد شوند. جنگو سیستمی دارد که به شما کمک میکند تا این database migrations را مدیریت کنید.
cd mysite
python manage.py migrate
شما خروجیای خواهید دید که در انتها شامل خطوط زیر است:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
خطوطی که در خروجی دیدید مربوط به database migrations هستند که توسط Django اعمال شدهاند. با اجرای مایگریشنهای اولیه، جداول مربوط به برنامههایی که در INSTALLED_APPS تعریف شدهاند در دیتابیس ایجاد میشوند.
در بخش Creating and applying migrations از این فصل، بیشتر با دستور مدیریتی migrate آشنا خواهید شد.
اجرای سرور توسعه (Development Server) در جنگو
جنگو همراه با یک وب سرور سبک ارائه میشود تا بتوانید کدهای خود را به سرعت اجرا کنید، بدون اینکه نیاز به پیکربندی یک سرور production داشته باشید.
وقتی سرور توسعهی Django را اجرا میکنید:
بهطور مداوم تغییرات کد شما را بررسی میکند.
به صورت خودکار reload میشود و نیازی نیست بعد از هر تغییر، آن را دستی راهاندازی کنید.
البته بعضی تغییرات مانند اضافهکردن فایلهای جدید ممکن است شناسایی نشوند؛ در این موارد باید سرور را به صورت دستی restart کنید.
برای اجرای سرور توسعه، دستور زیر را در shell prompt وارد کنید:
python manage.py runserver
باید خروجیای مشابه زیر ببینید:
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
August 16, 2025 - 13:15:40
Django version 5.0.14, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
حالا آدرس /http://127.0.0.1:8000 را در مرورگر خود باز کنید. باید صفحهای ببینید که نشان میدهد پروژه با موفقیت در حال اجرا است، همانطور که در شکل 1.3 نمایش داده شده است.
تصویر بالا نشان میدهد که Django در حال اجرا است. اگر به کنسول یا ترمینال خود نگاه کنید، درخواست GET که توسط مرورگر شما ارسال شده است را مشاهده خواهید کرد:
[01/Jan/2024 10:00:15] "GET / HTTP/1.1" 200 16351
هر درخواست http توسط سرور جنگو در console ثبت میشود. همچنین هر خطایی که هنگام اجرای سرور توسعه رخ دهد در console نمایش داده خواهد شد.
میتوانید سرور جنگو را روی یک host و port دلخواه اجرا کنید یا به Django بگویید که یک فایل settings مشخص را بارگذاری کند. برای مثال:
python manage.py runserver 127.0.0.1:8001 --settings=mysite.settings
وقتی با چند environment مختلف سروکار دارید که هرکدام نیاز به تنظیمات جداگانه دارند، میتوانید برای هر محیط یک فایل settings جدا ایجاد کنید.
این سرور فقط برای development طراحی شده و برای استفاده در production مناسب نیست. برای استقرار Django در محیط production، باید آن را به صورت یک WSGI application با وبسرورهایی مانند Apache، Gunicorn یا uWSGI اجرا کنید، یا به صورت یک ASGI application با وبسرورهایی مثل Daphne یا Uvicorn.
اطلاعات بیشتر دربارهی استقرار Django با وبسرورهای مختلف را میتوانید در این صفحه پیدا کنید.
در فصل ۱۷ توضیح داده شده که چگونه میتوانید یک محیط production برای پروژههای جنگو خود راهاندازی کنید.
تنظیمات پروژه در جنگو
بیایید فایل settings.py را باز کنیم و به تنظیمات پروژه نگاهی بیندازیم. Django چندین تنظیم پیشفرض در این فایل قرار داده است، اما اینها تنها بخشی از تمام تنظیمات جنگو موجود هستند. فهرست کامل تنظیمات به همراه مقادیر پیشفرضشان را میتوانید در این صفحه ببینید:
https://docs.djangoproject.com/en/5.0/ref/settings/
بیایید بعضی از تنظیمات مهم پروژه را مرور کنیم:
DEBUG: یک مقدار Boolean است که حالت debug پروژه را روشن یا خاموش میکند. اگر روی True قرار بگیرد، Django هنگام بروز خطاهای کنترلنشده خطا هارا با جزییات نمایش میدهد. در محیط production باید آن را روی False بگذارید. هرگز پروژه را با DEBUG=True در محیط production اجرا نکنید، چون دادههای حساس پروژه برای همه کاربران سایت افشا خواهند شد.
ALLOWED_HOSTS: در حالت debug یا هنگام اجرای تستها اعمال نمیشود. وقتی پروژه را به محیط production منتقل کردید و DEBUG=False شد، باید نام دامنه یا هاست خود را به این تنظیم اضافه کنید تا Django بتواند سایت به نام دامنه مشخص شده سرویس دهد.
INSTALLED_APPS: یکی از تنظیماتی است که در تمام پروژهها در حین توسعه نیاز به ویرایش دارد. این بخش به فریمورک جنگو میگوید چه برنامههایی در این سایت فعال هستند. بهطور پیشفرض شامل موارد زیر است:
django.contrib.admin: مدیریت سایت.
django.contrib.auth: فریمورک احراز هویت.
django.contrib.contenttypes: فریمورک مدیریت انواع محتوا.
django.contrib.sessions: فریمورک مدیریت سشنها.
django.contrib.messages: فریمورک پیامرسانی.
django.contrib.staticfiles: فریمورک مدیریت فایلهای استاتیک مانند CSS، JavaScript و تصاویر.
MIDDLEWARE: یک لیست است که شامل کد های واسطی است که باید اجرا شوند.
ROOT_URLCONF: ماژول Python را مشخص میکند که الگوهای root URL برنامه در آن تعریف شدهاند.
DATABASES: یک dictionary است که تنظیمات دیتابیسهای مورد استفاده در پروژه را نگه میدارد. همیشه باید یک دیتابیس پیشفرض وجود داشته باشد. پیکربندی پیشفرض از SQLite3 استفاده میکند.
LANGUAGE_CODE: زبان پیشفرض سایت Django را مشخص میکند.
USE_TZ: تعیین میکند پشتیبانی از timezone فعال باشد یا نه. Django بهطور پیشفرض از تاریخ و زمانهای وابسته به منطقه زمانی پشتیبانی میکند. این تنظیم وقتی پروژهای را با دستور startproject میسازید روی True قرار دارد.
نگران نباشید اگر الان همهی این تنظیمات برایتان روشن نیست؛ در فصلهای بعدی با هر کدام از آنها بیشتر آشنا خواهید شد.
پروژه و Applications در جنگو چیست ؟
در طول این کتاب، بارها با اصطلاحات project و application روبهرو خواهید شد.
در جنگو، یک پروژه در واقع یک نسخه نصب شده از Django همراه با تنظیمات آن است.
یک application مجموعهای از models، views، templates و URLs است. برنامهها با فریمورک تعامل میکنند تا قابلیتهای خاصی فراهم کنند و میتوانند در پروژههای مختلف هم استفاده شوند.
میتوانید یک project را مانند وبسایت خود در نظر بگیرید که شامل چندین application مثل وبلاگ، ویکی یا انجمن است؛ و هر کدام از این برنامهها میتوانند در پروژههای Django دیگر هم به کار بروند.
عکس 1.4 ساختار یک Django project را نشان میدهد.
ایجاد یک Application در جنگو
بیایید اولین Django application خود را بسازیم. ما قرار است یک blog application را از صفر پیادهسازی کنیم.
در shell prompt و از مسیر اصلی پروژه، دستور زیر را اجرا کنید:
python manage.py startapp blog
این دستور ساختار پایهی application را ایجاد میکند که به شکل زیر خواهد بود:
blog/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
فایلهای ایجادشده به این صورت هستند:
__init__.py: یک فایل خالی که به Python اعلام میکند پوشهی blog یک Python module است.
admin.py: جایی که میتوانید مدلها را ثبت کنید تا در پنل مدیریت پیشفرض جنگو نمایش داده شوند (استفاده از این قسمت اختیاری است).
apps.py: شامل تنظیمات اصلی blog application است.
migrations: این پوشه مایگریشنهای دیتابیس مربوط به برنامه را نگه میدارد. مایگریشنها تغییرات مدلها را دنبال میکنند و دیتابیس را هماهنگ میسازند. این پوشه یک فایل خالی __init__.py هم دارد.
models.py: شامل data models برنامه است. همهی Django applications باید یک فایل models.py داشته باشند، حتی اگر خالی بماند.
tests.py: جایی برای نوشتن تستهای مربوط به برنامه.
views.py: منطق اصلی برنامه در اینجا قرار میگیرد؛ هر view یک درخواست HTTP را دریافت میکند، آن را پردازش کرده و یک پاسخ برمیگرداند.
شروع ساخت Blog Data Models در جنگو
به یاد داشته باشید که یک Python object مجموعهای از داده و متدها است. Classes الگو یا طرحی برای ترکیب داده و عملکردها هستند. ایجاد یک class جدید به معنای تعریف یک نوع شیء جدید است که میتوانید نمونههایی از آن بسازید.
یک Django model منبع اطلاعات درباره رفتار دادههای شما است. این مدل در قالب یک Python class تعریف میشود که از django.db.models.Model ارثبری میکند. هر مدل به یک جدول دیتابیس نگاشت میشود و هر attribute از کلاس، نمایندهی یک database field خواهد بود.
وقتی یک مدل ایجاد میکنید، Django یک API قدرتمند در اختیار شما قرار میدهد تا بتوانید بهسادگی دادههای دیتابیس را استفاده کنید.
ما در این بخش database models مربوط به blog application را تعریف میکنیم. سپس برای مدلها database migrations ایجاد خواهیم کرد تا جداول دیتابیس مربوطه ساخته شوند. هنگام اجرای مایگریشنها، Django یک جدول برای هر مدل تعریفشده در پروژه خواهد ساخت.
models.py
ایجاد مدل Post
در اولین گام، یک Post Model تعریف میکنیم تا بتوانیم پست های بلاگ را در دیتابیس ذخیره کنیم.
کد زیر را به فایل models.py در blog application اضافه کنید. خطوط جدید به صورت bold مشخص شدهاند:
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
def __str__(self):
return self.title
این مدل داده برای پستهای وبلاگ است. پستها شامل یک title، یک برچسب کوتاه به نام slug و یک body خواهند بود. بیایید نگاهی به فیلدهای این مدل بیندازیم:
title: این فیلد برای عنوان پست است. این یک فیلد CharField است که در دیتابیس SQL به یک ستون VARCHAR تبدیل میشود.
slug: این یک فیلد SlugField است که در دیتابیس SQL به یک ستون VARCHAR تبدیل میشود. Slug یک برچسب کوتاه است که فقط شامل حروف، اعداد، خط زیر (
_) یا خط تیره (-) میباشد. یک پست با عنوان
Django Reinhardt: A legend of Jazz
میتواند slugای مانند این داشته باشد:django-reinhardt-legend-jazz
ما از فیلد slug برای ساخت URLهای زیبا و SEO-friendly برای پستهای وبلاگ در فصل ۲ استفاده خواهیم کرد.body: این فیلد برای ذخیره بدنهی پست است. این یک فیلد TextField است که در دیتابیس SQL به یک ستون TEXT تبدیل میشود.
ما همچنین یک متد __str__به کلاس مدل اضافه کردهایم. این متد پیشفرض Python برای برگرداندن یک رشته با ظاهری قابل خواندن توسط انسان از شیء است. Django از این متد برای نمایش نام شیء در بسیاری از مکانها مانند Django administration site استفاده خواهد کرد.
بیایید نگاهی بیندازیم به اینکه چطور این مدل و فیلدهای آن به یک جدول دیتابیس و ستونها ترجمه میشوند. نمودار زیر مدل Post و جدول دیتابیسی که Django هنگام همگامسازی مدل با دیتابیس ایجاد خواهد کرد را نشان میدهد:
افزودن فیلدهای datetime
اکنون ادامه میدهیم و فیلدهای مختلف datetime را به مدل Post اضافه میکنیم. هر پست باید در یک تاریخ و زمان مشخص منتشر شود. بنابراین به فیلدی برای ذخیره تاریخ و زمان انتشار نیاز داریم. همچنین میخواهیم تاریخ و زمان ایجاد شدن شیء Post و آخرین زمان تغییر آن را ذخیره کنیم.فایل models.py در blog application را به شکل زیر ویرایش کنید؛ خطوط جدید با bold مشخص شدهاند:
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
ما یک فیلد publish به مدل Post اضافه کردهایم. این یک فیلد DateTimeField است که در دیتابیس SQL به یک ستون DATETIME تبدیل میشود. از این فیلد برای ذخیره تاریخ و زمانی که پست منتشر میشود استفاده خواهیم کرد. ما از متد timezone.now به عنوان مقدار پیشفرض این فیلد استفاده کردهایم. توجه کنید که برای استفاده از این متد، ماژول timezone را ایمپورت کردهایم. متد timezone.now زمان فعلی را در قالبی برمیگرداند که به timezone آگاه است. میتوانید آن را نسخهی آگاه به منطقه زمانی از متد استاندارد Python یعنی datetime.now در نظر بگیرید.
روش دیگر برای تعریف مقادیر پیشفرض برای فیلدهای مدل، استفاده از مقادیر پیشفرض محاسبهشده توسط دیتابیس است. این قابلیت از نسخه Django 5 معرفی شد و به شما اجازه میدهد از توابع داخلی دیتابیس برای تولید مقادیر پیشفرض استفاده کنید. به عنوان مثال، کد زیر تاریخ و زمان فعلی سرور دیتابیس را به عنوان مقدار پیشفرض برای فیلد publish قرار میدهد:
from django.db import modelsfrom
django.db.models.functions import Now
class Post(models.Model):
# ...
publish = models.DateTimeField(db_default=Now())
برای استفاده از مقادیر پیشفرض تولیدشده توسط دیتابیس، به جای default از ویژگی db_default استفاده میکنیم. در این مثال، ما از تابع دیتابیس Now استفاده میکنیم. این تابع هدفی مشابه default=timezone.now دارد، با این تفاوت که به جای مقدار زمان تولیدشده توسط Python، از تابع ()NOW دیتابیس برای تولید مقدار اولیه استفاده میکند.
میتوانید اطلاعات بیشتر درباره ویژگی db_default را در این صفحه بخوانید:
https://docs.djangoproject.com/en/5.0/ref/models/fields/#django.db.models.Field.db_default
فهرست تمام توابع دیتابیس موجود را نیز میتوانید در این صفحه پیدا کنید:
https://docs.djangoproject.com/en/5.0/ref/models/database-functions/
بیایید با نسخه قبلی فیلد ادامه دهیم:
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
default sort order
پستهای وبلاگ معمولاً به صورت reverse chronological order نمایش داده میشوند؛ یعنی جدیدترین پستها در ابتدا قرار میگیرند.
برای مدل خودمان، یک default ordering تعریف میکنیم.
این ترتیب زمانی اعمال میشود که آبجکتها را از database دریافت میکنیم، مگر اینکه در یک query ترتیب متفاوتی مشخص شده باشد.
فایل models.py مربوط به اپلیکیشن blog را مطابق نمونهٔ زیر ویرایش کنید.
خطوط جدید با bold مشخص شدهاند:
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-publish']
def __str__(self):
return self.title
ما یک کلاس Meta داخل مدل اضافه کردهایم. این کلاس metadata مدل را تعریف میکند.
ما از attribute مربوط به ordering استفاده میکنیم تا به Django بگوییم نتایج را بر اساس فیلد publish مرتب کند.
این ترتیب زمانی اعمال میشود که در query ترتیب مشخصی تعیین نشده باشد.برای مشخص کردن ترتیب نزولی (descending order)، یک خط تیره قبل از نام فیلد قرار میدهیم:publish-
به این ترتیب، پستها بهصورت پیشفرض در reverse chronological order برگردانده میشوند.
اضافه کردن یک database index
بیایید یک database index برای فیلد publish تعریف کنیم.این کار عملکرد (performance) را برای query filtering یا مرتبسازی (ordering) نتایج بر اساس این فیلد بهبود میدهد.از آنجا که ما معمولاً از فیلد publish برای مرتبسازی نتایج استفاده میکنیم، انتظار داریم بسیاری از queryها از این index استفاده کنند.
فایل models.py مربوط به اپلیکیشن blog را ویرایش کنید و مطابق نمونهٔ زیر قرار دهید:
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-publish']
indexes = [
models.Index(fields=['-publish']),
]
def __str__(self):
return self.title
ما گزینهٔ indexes را به کلاس Meta مدل اضافه کردهایم.این گزینه به شما اجازه میدهد برای مدل خود database index تعریف کنید؛این index میتواند شامل یک یا چند فیلد باشد، بهصورت ascending یا descending تعریف شود، یا حتی شامل functional expressions و database functions باشد.ما یک index برای فیلد publish اضافه کردهایم.
برای تعریف index بهصورت descending، یک خط تیره قبل از نام فیلد قرار دادهایم.ایجاد این index در database migrations که بعداً برای مدلهای blog تولید خواهیم کرد، لحاظ میشود. Index ordering در MySQL پشتیبانی نمیشود.اگر از MySQL بهعنوان database استفاده کنید، index مربوط به descending بهصورت یک index معمولی ایجاد میشود.
برای اطلاعات بیشتر دربارهٔ نحوه تعریف indexes برای مدلها میتوانید به این لینک مراجعه کنید:
https://docs.djangoproject.com/en/5.0/ref/models/indexes
فعالسازی اپلیکیشن
ما باید اپلیکیشن blog را در پروژه فعال کنیم تا Django بتواند آن را شناسایی کند و جداول دیتابیس مربوط به مدلهای آن را ایجاد کند.فایل settings.py را ویرایش کنید و مقدار blog.apps.BlogConfig را به تنظیمات INSTALLED_APPS اضافه کنید.بخش مربوطه باید شبیه نمونهٔ زیر باشد؛
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog.apps.BlogConfig',
]
کلاس BlogConfig تنظیمات (configuration) مربوط به اپلیکیشن است.الان Django میداند که این اپلیکیشن برای این پروژه فعال شده و میتواند مدلهای این اپلیکیشن را بارگذاری (load) کند.
اضافه کردن یک فیلد status
یکی از قابلیتهای معمول در وبلاگها این است که بتوان پستها را بهصورت draft نگه داشت تا زمانی که آمادهٔ انتشار شوند.ما یک فیلد status به مدل اضافه میکنیم تا بتوانیم وضعیت پستهای وبلاگ را مدیریت کنیم.در اینجا از دو وضعیت Draft و Published برای پستها استفاده خواهیم کرد.فایل models.py مربوط به اپلیکیشن blog را ویرایش کنید تا مانند نمونهٔ زیر شود.خطوط جدید با bold مشخص شدهاند:
from django.db import models
from django.utils import timezone
class Post(models.Model):
class Status(models.TextChoices):
DRAFT = 'DF', 'Draft'
PUBLISHED = 'PB', 'Published'
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(
max_length=2,
choices=Status,
default=Status.DRAFT,
)
class Meta:
ordering = ['-publish']
indexes = [
models.Index(fields=['-publish']),
]
def __str__(self):
return self.title
ما کلاس Status را با subclass کردن از models.TextChoices تعریف کردهایم.گزینههای موجود برای post status عبارتند از DRAFT و PUBLISHED.مقادیر آنها بهترتیب DF و PB هستند و label یا نام قابلخواندن آنها Draft و Published است.Django نوعهایی از enumeration ارائه میدهد که میتوانید با subclass کردن آنها، choices را بهسادگی تعریف کنید.این نوعها بر پایهٔ شیٔ enum در کتابخانه استاندارد Python ساخته شدهاند.
میتوانید دربارهٔ enum در این لینک بیشتر بخوانید:
https://docs.python.org/3/library/enum.html
Enumeration typeهای Django تفاوتهایی نسبت به enum استاندارد دارند.
میتوانید این تفاوتها را در این لینک ببینید:
https://docs.djangoproject.com/en/5.0/ref/models/fields/#enumeration-types
ما میتوانیم از Post.Status.choices برای دریافت کل گزینهها استفاده کنیم،از Post.Status.names برای گرفتن نامهای گزینهها،از Post.Status.labels برای گرفتن نامهای قابلخواندن، و از Post.Status.values برای گرفتن مقادیر واقعی گزینهها.
ما همچنین یک فیلد جدید به نام status به مدل اضافه کردهایم که یک CharField است.این فیلد شامل پارامتر choices است تا مقدار آن به گزینههای موجود در Status محدود شود.همچنین با استفاده از پارامتر default، یک مقدار پیشفرض برای این فیلد تعیین کردهایم.
ما DRAFT را بهعنوان مقدار پیشفرض این فیلد قرار دادهایم.استفاده از enumeration typeها و تعریف کردن choices داخل model یک روش خوب و استاندارد است. این کار باعث میشود بتوانید label، value یا name مربوط به هر انتخاب را بهراحتی در هر جایی از کدتان استفاده کنید. میتوانید مدل Post را import کرده و در هر قسمت از کد از Post.Status.DRAFT برای اشاره به وضعیت Draft استفاده کنید. اکنون بیایید ببینیم چگونه میتوان با status choices تعامل داشت. دستور زیر را در shell prompt اجرا کنید تا Python shell باز شود:
python manage.py shell
سپس، خطوط زیر را تایپ کنید:
from blog.models import Post
>>> Post.Status.choices
شما enum choices را به صورت جفتهای value–label دریافت خواهید کرد، مانند این:
[('DF', 'Draft'), ('PB', 'Published')]
خط زیر را تایپ کنید:
Post.Status.labels
شما human-readable names مربوط به اعضای enum را به شکل زیر دریافت خواهید کرد:
human-readable name یعنی اسم واضح و خوانایی که برای نمایش به کاربر استفاده میشود.
['Draft', 'Published']
خط زیر را تایپ کنید:
Post.Status.values
شما values مربوط به اعضای enum را به شکل زیر دریافت خواهید کرد.اینها همان مقادیری هستند که میتوانند برای فیلد status در database ذخیره شوند:
['DF', 'PB']
خط زیر را تایپ کنید:
Post.Status.names
['DRAFT', 'PUBLISHED']
اضافه کردن یک many-to-one relationship
پستها همیشه توسط یک نویسنده نوشته میشوند.ما یک رابطه بین users و posts ایجاد میکنیم تا مشخص شود هر پست را کدام کاربر نوشته است.Django یک authentication framework همراه خود دارد که مدیریت user accounts را انجام میدهد.این سیستم احراز هویت در پکیج django.contrib.auth قرار دارد و شامل مدل User است.برای تعریف رابطه بین users و posts، از تنظیم AUTH_USER_MODEL استفاده میکنیم.این تنظیم بهصورت پیشفرض به auth.User اشاره میکند.این قابلیت به شما اجازه میدهد در صورت نیاز، user model متفاوتی برای پروژهٔ خود تعریف کنید.
فایل models.py مربوط به اپلیکیشن blog را ویرایش کنید تا مانند نمونهٔ زیر باشد.
from django.conf import settings
from django.db import models
from django.utils import timezone
class Post(models.Model):
class Status(models.TextChoices):
DRAFT = 'DF', 'Draft'
PUBLISHED = 'PB', 'Published'
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='blog_posts'
)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(
max_length=2,
choices=Status,
default=Status.DRAFT
)
class Meta:
ordering = ['-publish']
indexes = [
models.Index(fields=['-publish']),
]
def __str__(self):
return self.title
ما settings پروژه را import کردهایم و یک فیلد author به مدل Post اضافه کردهایم.این فیلد یک many-to-one relationship با default user model ایجاد میکند؛یعنی هر پست توسط یک user نوشته میشود و هر user میتواند تعداد نامحدودی پست بنویسد.برای این فیلد، Django یک foreign key در database ایجاد میکند که از primary key مدل مرتبط استفاده میکند.
پارامتر on_delete مشخص میکند وقتی شیء مرتبط حذف شد، چه رفتاری انجام شود.این مورد مخصوص Django نیست و یک استاندارد SQL است.با استفاده از CASCADE، تعیین میکنید که اگر user حذف شود، database تمام پستهای مرتبط با او را نیز حذف کند.میتوانید تمام گزینههای ممکن را در این لینک ببینید:
https://docs.djangoproject.com/en/5.0/ref/models/fields/#django.db.models.ForeignKey.on_delete
ما از related_name استفاده کردیم تا نام reverse relationship از User به Post را تعیین کنیم.این کار باعث میشود بتوانیم از طریق آبجکت user، پستهای مرتبط را بهسادگی با دستور user.blog_posts دریافت کنیم.(در ادامه بیشتر دربارهٔ این موضوع یاد میگیریم.)
Django انواع مختلفی از fieldها را ارائه میدهد که میتوانید برای مدلها استفاده کنید.تمام این field typeها را در این لینک میتوانید پیدا کنید:
https://docs.djangoproject.com/en/5.0/ref/models/fields/
مدل Post اکنون کامل شده است و میتوانیم آن را با database همگامسازی کنیم.
ایجاد و اعمال migrations
اکنون که یک data model برای پستهای وبلاگ داریم، لازم است database table مربوط به آن را ایجاد کنیم.Django یک migration system دارد که تغییرات اعمالشده روی مدلها را دنبال میکند و این تغییرات را به database منتقل میکند.دستور migrate تمام migrations مربوط به اپلیکیشنهایی را که داخل INSTALLED_APPS هستند اجرا میکند.این دستور database را با مدلهای فعلی و migrations موجود synchronize میکند.ابتدا باید یک initial migration برای مدل Post بسازیم.در root directory پروژه، دستور زیر را در shell prompt اجرا کنید:
python manage.py makemigrations blog
blog/migrations/0001_initial.py
- Create model Post
- Create index blog_post_publish_bb7600_idx on field(s)
-publish of model post
python manage.py sqlmigrate blog 0001
BEGIN;
--
-- Create model Post
--
CREATE TABLE "blog_post" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"title" varchar(250) NOT NULL,
"slug" varchar(250) NOT NULL,
"body" text NOT NULL,
"publish" datetime NOT NULL,
"created" datetime NOT NULL,
"updated" datetime NOT NULL,
"status" varchar(10) NOT NULL,
"author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED);
--
-- Create blog_post_publish_bb7600_idx on field(s) -publish of model post
--
CREATE INDEX "blog_post_publish_bb7600_idx" ON "blog_post" ("publish" DESC);
CREATE INDEX "blog_post_slug_b95473f2" ON "blog_post" ("slug");
CREATE INDEX "blog_post_author_id_dd7a8485" ON "blog_post" ("author_id");
COMMIT;
خروجی دقیق به databaseای که استفاده میکنید بستگی دارد.
خروجی بالا برای SQLite تولید شده است.
همانطور که در خروجی میبینید، Django نام جدولها را با ترکیب نام اپلیکیشن و نام مدل بهصورت lowercase تولید میکند (blog_post).
اما شما میتوانید یک نام دلخواه برای جدول دیتابیس مدل خود در کلاس Meta و با استفاده از attribute مربوط به db_table مشخص کنید.
Django یک ستون id بهصورت auto-increment ایجاد میکند که بهعنوان primary key برای هر مدل استفاده میشود.
ولی شما میتوانید این رفتار را تغییر دهید و روی یکی از فیلدهای مدل،
primary_key=True
قرار دهید تا آن فیلد primary key شود.
ستون پیشفرض id از نوع integer است و به شکل خودکار افزایش مییابد.
این ستون همان فیلد idای است که Django بهصورت خودکار به مدل شما اضافه میکند.
سه database index زیر ایجاد شدهاند:
- یک index بهصورت descending روی ستون publish.
این همان index است که ما بهطور صریح از طریق گزینهٔ indexes در کلاس Meta مدل تعریف کرده بودیم. - یک index روی ستون slug،
چون فیلدهای SlugField بهصورت پیشفرض یک index ایجاد میکنند. - یک index روی ستون author_id،
چون فیلدهای ForeignKey بهصورت پیشفرض index ایجاد میکنند.
اکنون بیایید مدل Post را با database table مربوط به آن یعنی blog_post مقایسه کنیم:
شکل 1.6 نشان میدهد که model fields چگونه با ستونهای database table مطابقت دارند.بیایید database را با مدل جدید sync کنیم.برای اعمال migrations موجود، دستور زیر را در shell prompt اجرا کنید:
python manage.py migrate
Applying blog.0001_initial...
OK
ما migrations مربوط به اپلیکیشنهایی که در INSTALLED_APPS قرار دارند — شامل اپلیکیشن blog — را اعمال کردیم.بعد از اجرای migrations، database وضعیت فعلی مدلها را منعکس میکند.اگر فایل models.py را ویرایش کنید و فیلدی را اضافه، حذف یا تغییر دهید، یا مدل جدیدی بسازید، باید یک migration جدید با استفاده از دستور makemigrations ایجاد کنید. هر migration به Django اجازه میدهد تا تغییرات مدلها را دنبال کند.سپس باید migration جدید را با استفاده از دستور migrate اعمال کنید تا database با مدلهای فعلی شما هماهنگ باقی بماند.
ایجاد یک administration site برای مدلها
حالا که مدل Post با database همگامسازی شده است، میتوانیم یک administration site ساده برای مدیریت پستهای وبلاگ ایجاد کنیم.Django یک administration interface داخلی دارد که برای ویرایش محتوا بسیار کاربردی است.
این سایت مدیریت بهصورت داینامیک و با خواندن model metadata ساخته میشود و یک رابط آمادهبرایتولید (production-ready) برای مدیریت محتوا ارائه میدهد.
میتوانید بدون هیچ افزونهٔ اضافهای از آن استفاده کنید و فقط تعیین کنید که مدلها چگونه در آن نمایش داده شوند.
اپلیکیشن django.contrib.admin از قبل داخل تنظیمات INSTALLED_APPS قرار دارد، بنابراین نیازی نیست آن را اضافه کنید.
ایجاد یک superuser
ابتدا لازم است یک کاربر بسازید تا بتوانید administration site را مدیریت کنید.
دستور زیر را اجرا کنید:
python manage.py createsuperuser
خروجی زیر را خواهید دید.
نام کاربری، ایمیل و رمز عبور دلخواه خود را وارد کنید:
Username (leave blank to use 'admin'): admin
Email address: admin@admin.com
Password: ********
Password (again): ********
سپس پیام موفقیت زیر نمایش داده میشود:
Superuser created successfully.
ما همین حالا یک کاربر administrator با بیشترین سطح دسترسی ایجاد کردیم.
Django administration site
سرور توسعه را با دستور زیر اجرا کنید:
python manage.py runserver
سپس در مرورگر خود این آدرس را باز کنید:
http://127.0.0.1:8000/admin/
باید صفحهٔ ورود (login) مربوط به administration site را ببینید، همانطور که در Figure 1.7 نشان داده شده است.
با استفاده از credentials همان user که در مرحلهٔ قبل ساخته بودید وارد شوید.
صفحهٔ administration site index را خواهید دید؛ همانطور که در Figure 1.8 نشان داده شده است.






