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

ورژن 2.2

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

نوشتن اولین پروژه جنگو: بخش دوم

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

تنظیم پایگاه‌داده

حالا، mysite/settings.py رو باز کنید. این یک ماژول ساده پایتون هست با یک‌سری متغیر سطح ماژول که نمایشگر تنظیمات جنگو هستن.

به صورت پیش‌فرض، تنظیمات پایگاه‌داده جنگو از SQLite استفاده می‌کنن. اگر شما در کار با پایگاه‌های داده تازه‌کارید یا فقط علاقه دارید که فعلا جنگو رو امتحان کنید، SQLite ساده‌ترین انتخابه. چون به صورت پیش‌فرض در پایتون وجود داره و شما برای کار باهاش نیاز نیست که چیز دیگه‌ای نصب کنید. زمانی که اولین پروژه جدی خودتون رو شروع می‌کنید، شاید بخواهید که از پایگاه‌داده‌های بزرگ‌تری مثل PostgreSQL استفاده کنید تا با مشکلات تغییر دیتابیس مواجه نشید.

اگر می‌خواهید که از دیتابیس دیگه‌ای استفاده کنید، دیتابیس مورد نظرتون رو نصب کنید و مقادیر موجود در DATABASES ‘default’ رو برای اتصال به دیتابیس مورد نظرتون تغییر بدید.

  • ENGINE – مثل ‘django.db.backends.sqlite3’, ‘django.db.backends.postgresql’, ‘django.db.backends.mysql’, یا ‘django.db.backends.oracle’. بقیه پایگاه‌های داده هم موجود هستند.

  • NAME - نام دیتابیس شماست. اگر از SQLite استفاده می‌کنید، دیتابیس در یک فایل در کامپیوتر شما ذخیره می‌شه، در این مورد NAME باید آدرس کامل و مشخص اون فایل همراه با اسم اون فایل باشه. مقدار پیش‌فرض os.path.join(BASE_DIR, ‘db.sqlite3’) دیتابیس رو در یک فایل درون پوشه‌ی پروژه ذخیره خواهد کرد.

اگر شما از SQLite به عنوان دیتابیس‌تون استفاده نمی‌کنید، تنظیمات اضافه‌ای مثل USER، PASSWORD و HOST باید اضافه بشن. برای اطلاعات بیشتر این لینک مربوط به DATABASES رو ببینید.

برای پایگاه‌های داده غیر از SQLite
اگر از پایگاه‌داده‌ای غیر از SQLite استفاده می‌کنید، مطمئن بشید که قبل‌ش دیتابیس رو ساختید. این کار رو می‌تونید به وسیله “CREATE DATABASE database_name;” در ابزار خط فرمان دیتابیس‌تون انجام بدید.
همچنین مطمئن بشید که دیتابیس در mysite/settings.py اجازه «ساخت دیتابیس» رو داره. این در ساخت اتوماتیک پایگاه‌داده‌های آزمایشی نیاز می‌شه که در ادامه این آموزش به‌شون می‌رسیم.
اما اگر از SQLite استفاده می‌کنید هیچ‌کدوم از این کارها رو نیاز ندارید که انجام بدید. فایل پایگاه‌داده زمانی که نیاز هست به صورت خودکار ساخته می‌شه.
حالا که دارید mysite/settings.py رو ویرایش می‌کنید، TIME_ZONE رو روی موقعیت زمانی خودتون ست کنید. یعنی ‘ASIA/TEHRAN’.

به تنظیماتِ INSTALLED_APPS در بالای فایل دقت کنید. اون لیست نام تمام اَپ‌های فعال در پروژه‌تون رو نگه می‌داره. اَپ‌ها(app) می‌تونن در پروژه‌های مختلفی استفاده بشن و شما می‌تونین اون‌ها رو به شکل پکیج‌هایی برای استفاده از دیگر پروژه‌ها و آدم‌های دیگه توزیع کنین.

به صورت پیش‌فرض INSTALLED_APPS شامل اپ‌های زیر هست که همه‌شون به صورت پیش‌فرض در جنگو وجود دارن:

این برنامه‌ها به صورت پیش‌فرض برای راحتی در انجام کارهای مشترکی که در اکثر پروژه‌ها وجود دارند اضافه شدن. بعضی از این برنامه‌ها حداقل از یک جدول دیتابیس استفاده می‌کنن، پس قبل از استفاده از اون‌ها باید این جداول رو در دیتابیس (پایگاه‌داده‌مون) بسازیم. برای این‌کار دستور زیر رو اجرا کنید:

python manage.py migrate

دستور migrate به تنظیمات موجود در INSTALLED_APPS نگاه می‌کنه و تمام جداول دیتابیس مورد نیاز رو در پایگاه‌ داده‌ای که در تنظیمات فایل mysite/settings.py تنظیم شده، ایجاد می‌کنه. شما هنگام انجام این کار پیام‌ انجام شدن کار رو برای هر کدوم از این جداول می‌بینید. اگر بیشتر علاقمند بودید دستور \dt (PostgreSQL), SHOW TABLES; (MySQL), .schema (SQLite), یا SELECT TABLE_NAME FROM USER_TABLES; (Oracle) رو در خط فرمان‌ دیتابیس‌تون اجرا کنید تا جداول ساخته شده توسط جنگو رو مشاهده کنید.

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


ساخت مدل‌ها

حالا نوبت اینه که مدل‌هامون رو تعریف کنیم - به صورت پایه، یعنی لایه‌های دیتابیس شما، با یک‌سری چیزهای اضافه!

فلسفه

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

این شامل کوچ‌ها (migrations) می‌شه - برخلاف فریم‌ورک Ruby On Rails مثلا؛ کوچ‌ها به طور کامل از فایل‌های مدل شما اجرا می‌شن و به طور پایه فقط یک تاریخچه هستن از زمان‌هایی که جنگو دیتابیس شما رو آپدیت می‌کنه تا با مدل‌های فعلی‌تون هم‌سان بشه.


در اپ نظرسنجی ساده ما، ما دو مدل می‌سازیم. Question و Choice. یک Question دارای یک سوال و یک زمان انتشار هست. یک Choice هم دو فیلد داره: متن انتخاب، و رای دادن. هر Choice در ارتباط هست با یک Question.
این مفاهیم با استفاده از کلاس‌ها در پایتون پیاده‌سازی می‌شن. فایل polls/models.py رو مثل زیر، ویرایش کنید:

polls/models.py:

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

کد بالا ساده‌ست، هر مدل به صورت یک کلاس نمایان شده؛ که خود این کلاس، یک زیر کلاس از django.db.models.Model هست. هر مدل دارای یک‌سری متغیر کلاسی هست که هر کدوم از این متغیرها هم نماینگر یک فیلد در مدل شما هستند.

هر فیلد نمایانگر یک نمونه از فیلد کلاسی است - به طور مثال CharField برای فیلدهای حاوی کاراکترها استفاده می‌شود و DateTimeField برای تاریخ و زمان. اون‌ها به جنگو می‌گن که در هر فیلد چه نوع داده‌هایی نگه‌داری می‌شن.

نام هر فیلد (مثلا question_text یا pub_date) یک نمونه‌ای است از نام اون فیلد در فرمت مورد پسند ماشین - کامیپوتر - و شما از این اسم‌ها در کد پایتون‌تون استفاده می‌کنید؛ و دیتابیس شما اون رو به عنوان نام ستون‌ها استفاده می‌کنه.

از اولین آرگومان اختیاری هر فیلد می‌شه استفاده کرد تا یک اسم مورد پسند برای آدم‌ها انتخاب کرد. این در بخش‌های مختلف دیگه‌ی جنگو هم استفاده می‌شه. اگر فیلد این آرگان رو نداشته باشه، جنگو به صورت پیش‌فرض از نام مورد پسند ماشین، استفاده می‌کنه. در مثال بالا، ما فقط اسم مورد پسند انسان رو برای فیلد Question.pub_date استفاده کردیم. برای بقیه فیلدها در این مدل، نام مورد پسند ماشین به جای نام مورد پسند انسان، استفاده می‌شه.

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

یک فیلد همچنین می‌تونه انواع و اقسام آرگومان‌های دل‌خواه رو داشته باشه. در این مورد، ما مقدار پیش‌فرض votes رو گذاشتیم صفر.

در آخر، توجه کنید که رابطه‌ها با استفاده از ForeignKey تعریف شده. این به جنگو می‌گه که هر Choice در رابطه‌ست با یک Question. جنگو تقریبا اکثر روابط موجود در دیتابیس رو پشتیبانی می‌کنه. many-to-one, many-to-many, و one-to-one.



فعال‌سازی مدل‌ها

این مقدار کوچیک از کد، به جنگو مقدار زیادی اطلاعات داد. با اون‌ها حالا جنگو می‌تونه:

  • جداول مورد نیاز برای این اپ رو در دیتابیس بسازه.

  • یک API برای دسترسی پایتون به اشیا Question و Choice بسازه.

اما قبل از هر کاری ما باید به پروژه‌مون بگیم که اپ polls نصب شده.

فلسفه

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

برای اضافه کردن این اپ به پروژه‌مون، ما باید اون رو در کلاس تنظیمات جنگو در بخش INSTALLED_APPS اضافه کنیم. کلاس PollsConfig در فایل polls/apps.py به صورت آدرس‌دهی نقطه‌ای می‌شه ‘polls.apps.PollsConfig’. فایل mysite/settings.py رو ویرایش کنید و آدرس نقطه‌ای رو در تنظیمات INSTALLED_APPS اضافه کنید. باید چیزی شبیه به این بشه:

mysite/settings.py:

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

حالا جنگو می‌دونه که باید اپ polls رو هم ببینه. بیاید یک دستور دیگه رو اجرا کنیم:

python manage.py makemigrations polls

حالا باید یک چیزی شبیه به این ببینید:

Migrations for 'polls':
  polls/migrations/0001_initial.py:
    - Create model Choice
    - Create model Question
    - Add field question to choice

با اجرا دستور makemigrations شما در واقع به جنگو می‌گید که تغییراتی در مدل‌هاتون دادید (در این مورد شما یک مدل جدید ساختید) و دوست دارید که تغییرات در یک migration ذخیره بشوند.

Migration‌ها در واقع چگونگی نحوه دخیره‌سازی تغییرات در مدل‌هاتون (و درواقع در دیتابیس‌تون) هستند- اون‌ها فقط فایل‌هایی روی هارد هستند. می‌تونید Migration مدل جدیدتون رو رو بخونید، اون یک فایل به اسم polls/migrations/0001_initial.py هست. نترسید! لازم نیست که هر بار این دستور رو می‌زنید، این فایل‌ها رو بخونید، اما این فایل‌ها برای ویرایش توسط انسان بهینه‌سازی شدند، وقتی که شما می‌خواهید به صورت دستی مشخص کنید که تغییرات چطوری در مدل‌ها و دیتابیس اعمال بشند.

دستوری وجود داره که بعد از اجرا، تغییرات موجود در Migrationها رو به صورت خودکار در دیتابیس‌تون اعمال می‌کنه - اسم‌ش migrate هست و بزودی می‌بینیدش - اما اول، بیاید ببینیم Migration روی کدوم SQL اجرا می‌شه و درواقع چی‌کار می‌کنه:

Migrations for 'polls':
  python manage.py sqlmigrate polls 0001

شما باید چیزی شبیه به این رو ببینید:

BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL
);
--
-- Create model Question
--
CREATE TABLE "polls_question" (
    "id" serial NOT NULL PRIMARY KEY,
    "question_text" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL;
ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT;
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
ALTER TABLE "polls_choice"
  ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id"
    FOREIGN KEY ("question_id")
    REFERENCES "polls_question" ("id")
    DEFERRABLE INITIALLY DEFERRED;

COMMIT;

به نکات زیر دقت کنید:

  • خروجی بالا کاملا بستگی به نوع دیتابیس مورد استفاده شما داره. نمونه بالا برای PostgreSQL تولید شده.

  • نام جداول به صورت اتوماتیک از ترکیب نام اپ (polls) و نام مدل‌های question و choice با حروف کوچک ساخته شده. (شما می‌تونید این رفتار رو تغییر بدید.)

  • کلیدهای اصلی (Primary keys) یا IDها به صورت اتوماتیک اضافه شدن. (این رو هم می‌تونید تغییر بدید.)

  • به صورت عمومی جنگو "_id” رو به فیلد foreign key می‌چسبونه. (بله! این رو هم می‌تونید بازنویسی‌ش کنید.)

  • رابطه foreign key با محدودیت‌های FOREIGN KEY شفاف و مشخص می‌شه. راجع به بخش DEFERRABLE نگران نباشید؛ اون فقط به PostgreSQL می‌گه که تا پایان کار، foreign key رو پیش نبره.

  • این متناسب با دیتابیسی هست که استفاده می‌کنید. پس فیلد‌های مخصوص نوع دیتابیس مثل auto_increment (MySQL), serial (PostgreSQL), یا integer primary key autoincrement (SQLite) به صورت خودکار هندل می‌شوند. همچنین این قضیه برای کوتیشن‌های نام فیلدها هم وجود داره - مثل دابل کوتیشن‌ها یا تک کوتیشن‌ها.

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

اگر بیشتر علاقه‌مند هستید، می‌تونید دستور python manage.py check رو اجرا کنید؛ این دستور بدون دست زدن به دیتابیس یا انجام Migrations چک می‌کنه که آیا مشکلی در پروژه‌تون ایجاد می‌شه یا نه؟

حالا، دستور migrate رو دوباره اجرا کنید تا جداول مربوط به مدل‌تون در دیتابیس ساخته بشه:

python manage.py migrate


Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Rendering model states... DONE
  Applying polls.0001_initial... OK

دستور migrate همه‌ی migrationهایی که هنوز اعمال نشدند رو می‌گیره (جنگو با استفاده از یک جدول خاص در دیتابیس‌تون به نام django_migrationsجنگو کنترل می‌کنه که چه migrationهایی انجام شدند) و اون‌ها رو در دیتابیس‌تون اعمال می‌کنه. - درواقع مدل‌های شما رو با دیتابیس‌تون هماهنگ و سینک می‌کنه.

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

  • مدل‌تون رو تغییر بدید. (در models.py)

  • دستور python manage.py makemigrations رو برای ساخت migrations اون تغییرات اجرا کنید.

  • دستور python manage.py migrate رو اجرا کنید تا تغییرات در دیتابیس‌تون اعمال بشن.

دلیل این‌که دستورهای جدا برای ساخت و اعمال migrationsها وجود داره این هست که شما بتونید اون‌ها رو در برنامه کنترل ورژن خودتون کامیت کنید و همراه با اپ ارسال‌شون کنید؛ این فقط فرآیند توسعه رو ساده‌تر نمی‌کنه، بلکه برای سایر توسعه‌دهندگان هم قابل استفاده‌ست.

اگر اطلاعات کاملی از کارهایی که manage.py انجام می‌ده می‌خواهید، [داکیومنت‌های django-admin](django-admin documentation) رو بخونید.



بازی کردن با APIها

حالا، بیاید یک نگاهی به خط فرمان تعاملی پایتون بندازیم و با APIهای آزاد و رایگانی که جنگو به‌مون می‌ده، بازی کنیم. برای اجرا کردن خط فرمان پایتون، از این دستور استفاده کنید:

python manage.py shell

ما از کد بالا به جای این‌که به صورت ساده بنویسیم “python” استفاده کردیم، چون manage.py متغیر DJANGO_SETTINGS_MODULE رو طوری تنظیم می‌کنه که مسیر ایمپورت پایتون رو به فایل mysite/settings.py بده.

وقتی در خط فرمان بودید، این APIها رو تست کنید:


>>> from polls.models import Choice, Question  # Import the model classes we just wrote.

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

# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

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

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

# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() displays all the questions in the database.
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>

یک دقیقه صبر کنید. <Question: Question object (1)> نمایانگر خوبی برای این شی نیست. بیاید با ویرایش مدل Question (قاعدتا در فایل polls/models.py ) و اضافه کردن متد str() به هر دو Question و Choice درستش کنیم.

polls/models.py:

from django.db import models

class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

خیلی مهمه که متدهای str() رو به مدل‌هاتون اضافه کنید. نه فقط به خاطر راحتی خودتون حین کار با خط فرمان، بلکه به این خاطر که اشیا و نمایش‌دهنده‌هاشون در روند خودکار ساخت بخش ادمین استفاده می‌شن.

بیاید یک متد دل‌خواه به این مدل اضافه کنیم:

polls/models.py:

import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

به نحوه اضافه کردن import datetime و from django.utils import timezone، برای اضافه کردن ماژول پایتونی استاندارد datetime و ابزار زمان - مکان جنگو در django.utils.timezone دقت کنید. اگر شما با کارکردن با موقعیت‌های زمانی در پایتون آشنا نیستید، می‌تونید از این لینک، چیزهایی یاد بگیرید: zone support docs.

این تغییرات رو ذخیره کنید و دوباره خط فرمان پایتون رو باز کنید با دستور python manage.py shell:

>>> from polls.models import Choice, Question

# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>

# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# Choice objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>

# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

برای اطلاعات بیشتر در رابطه با مدل‌ها Accessing related objects رو ببینید.



مقدمه‌ای بر ادمین جنگو

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


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

ساخت کاربر مدیر

اول ما نیاز داریم که یک کاربر که بتونه در بخش مدیریت سایت لاگین کنه بسازیم. دستور زیر رو اجرا کنید.

python manage.py createsuperuser

نام‌کاربری مورد نظرتون رو وارد کنید و بعد اینتر بزنید.

Username: admin

حالا نوبت آدرس ای‌میل هست:

Email address: admin@example.com

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

Password: **********
Password (again): *********
Superuser created successfully.


اجرا کردن سرور توسعه

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

اگر سرورتون در حال اجرا نبود، اون رو با دستور زیر اجرا کنید:

python manage.py runserver

حالا مرورگر خودتون رو باز کنید و به آدرس “/admin/” برید. http://127.0.0.1:8000/admin/ باید چیزی شبیه به صفحه ورود زیر ببینید:

صفحه ورود ادمین جنگو



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

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

صفحه اول ادمین جنگو

شما باید یک تعداد کمی محتوا قابل ویرایش ببینید: گروه‌ها (groups) و کاربران (users). اون‌ها با استفاده از فریم‌ورک تایید هویت جنگو django.contrib.auth اضافه شدند.



اپ polls رو در بخش ادمین قابل ویرایش کنید

اما اپ نظرسنجی ما کجاست؟ اون در صفحه مدیریت نمایش داده نمی‌شه.

فقط یک‌کار باید انجام بشه: ما باید به ادمین بگیم که اشیا Question رابط مدیریت دارند. برای انجام این کار، فایل polls/admin.py رو باز کنید و مثل پایین، ویرایشش کنید:

polls/admin.py:

from django.contrib import admin

from .models import Question

admin.site.register(Question)



کارکرد بخش ادمین رو ببینید!

حالا، ما Question رو اضافه کردیم. جنگو می‌دونه که حالا باید در صفحه ادمین اون رو نمایش بده:

صفحه سوالات ادمین جنگو

روی “Questions” کلیک کنید. حالا در صفحه “change list” سوالات هستید. این صفحه همه سوالات موجود در دیتابیس رو به شما نمایش می‌ده و می‌تونید انتخاب کنید که کدوم یکی از اون‌ها رو ویرایش کنید. یک سوال “?what's up” وجود داره که ما قبلا ساخته بودیم‌ش:

صفحه ویرایش ادمین جنگو

روی “?what's up” کلیک کنید:

صفحه ویرایش ادمین جنگو

چیزهایی که این‌جا باید به‌شون توجه کنید:

  • فرم ویرایش به صورت خودکار با توجه به مدل Question ساخته شده.

  • انواع فیلدهای مختلف در مدل‌ها (DateTimeField, CharField) مطابق با ویجت HTML مناسب‌شون هستن. هر نوع از فیلد می‌دونه که چطور باید در بخش ادمین جنگو ظاهر بشه.

  • هر فیلد DateTimeField یک شورت‌کات جاوااسکریپت داره. تاریخ شورت‌کارت “Today” و یک تقویم پاپ‌آپ داره، و زمان یک شورت‌کارت “Now” و یک پاپ‌آپ باحال که لیستی از زمان‌های پرکاربرد هست رو داره.

پایین صفحه چندتا گزینه هست:

  • گزینه Save - تغییرات رو ذخیره می‌کنه و شما رو به صفحه Change-list این نوع شی می‌بره.

  • گزینه Save and continue editing - تغییرات رو ذخیره می‌کنه و صفحه ادمین رو برای این شی دوباره تازه‌سازی می‌کنه.

  • گزینه Save and add another - تغییرات رو ذخیره می‌کنه و یک فرم خام برای اضافه کردن این نوع از شی می‌آره.

  • گزینه Delete - صفحه تایید حذف رو نمایش می‌ده.

اگر مقدار “Date published” با زمانی که شما سوال رو در بخش اول ساختید برابر نیست احتمالا به این معناست که فراموش کردید مقدار درست رو برای **TIME_ZONE تنظیم کنید. تغییرش بدید و. بعد صفحه رو بارگذاری مجدد کنید و چک کنید که مقدار صحیح ظاهر بشه.

فیلد “Date published” رو با کلیلک بر روی شورت‌کات‌های “Today” و “Now” تغییر بدید. حالا روی “Save and continue editing” کلیک کنید. بعد روی “History” در سمت راست کلیک کنید. شما یک لیست از تمام تغییراتی که در بخش مدیریت اعمال شده رو خواهید دید؛ با زمان و نام‌کاربری کسی که اون تغییرات رو انجام داده:

صفحه تغییرات ادمین جنگو

وقتی که با API مدل‌ها آشناتر شدید، بخش سوم رو برای یادگیری نحوه اضافه کردن ویوها بیشتر به اپ‌‌مون بخونید.