1 - شروع کار با جانگو

وب‌سایت‌های امروز، در پشتِ صحنه، نرم‌افزارهای کارب144 ردی غنی و کاملی هستند که مانند برنامه‌های رومیزی کاملاً توسعه‌یافته رفتار می‌کنند. پایتون مجموعه‌ی بزرگ از ابزارها به نام جانگو برای ساختن برنامه‌های کاربردی تحت وب دارد. جانگو یک چهارچوب یا فریم‌ورک برای وب است— مجموعه‌ای از ابزارها که برای کمک به شما در ساختن وب‌سایت‌های تعاملی طرّاحی شده‌اند. در این فصل خواهید آموخت که چگونه از جانگو (https://djangoproject.com/) برای ساختن پروژه‌ای به نام Learning Log استفاده کنید— یک سیستم گزارش کار آنلاین که به شما امکان می‌دهد که دانسته‌هایی که درباره‌ی موضوعات خاصّی کسب کرده‌اید ثبت کنید.

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

جانگو می‌تواند به درخواست‌های صفحه پاسخ دهد و خواندن و نوشتن در پایگاه داده، مدیرّیت کاربران و … را ساده می‌کند. در فصل‌های ۱۹ و۲۰ این پروژه را بهبود می‌بخشید و سپس آن‌ را روی یک سرور مستقر می‌کنید تا خود و دوستانتان بتوانند از آن استفاده کنند.

2 - برپا کردن یک پروژه

هنگام شروع یک پروژه اوّلین کار شرح دادن پروژه در ی146 145 ک مجموعه مشخّصات است. سپس یک محیط مجازی برپا می‌کنید که در آن پروژه را خواهید ساخت.

نوشتن مشخّصات

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

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

وقتی در مورد موضوع جدیدی چیزی می‌آموزید، ثبت کردن آنچه آموخته‌اید می‌تواند در پیگیری و مرور اطّلاعات کمک کند. یک برنامه‌ی خود می‌تواند این فرآیند را کارآمد کند.

ساختن یک محیط مجازی

اوّلین قدم برای کار کردن با جانگو ساختن یک محیط مجازی است. یک محیط مجازی جایی در سیستم شماست که می‌توانید بسته‌ها را در آن نصب و آن را از دیگر بسته‌های پایتون مجزّا کنید. جدا کردن کتابخانه‌های یک پروژه از دیگر پروژه‌ها اکنون کاری سودمند و در آینده، زمانی که بخواهیم در فصل ۲۰ پروژه را در یک سرور مستقر کنیم، الزامی است.

پوشه‌ای جدید به نام learning_log برای پروژه‌ی خود بسازید و در یک نشست ترمینال وارد آن پوشه شوید، ‌سپس برای ساختن محیط مجازی کد زیر را وارد کنید:

1
2
learning_log$ python -m venv ll_env
learning_log$

اینجا ماژول محیط مجازی venv را اجرا کرده و از آن برای ساختن یک محیط مجازی جدید به نام ll_env استفاده می‌کنیم. (توجّه کنید که این نام با دو حرف l شروع می‌شود نه دو عدد 1). اگر برای اجرای برنامه‌ها یا نصب بسته‌ها از دستوری مانند python3 استفاده می‌کرده‌اید، اکنون نیز آن را به کار ببرید.

فعّال‌سازی محیط مجازی

اکنون باید با فرمان زیر محیط مجازی را فعّال کنیم:

1
2
learning_log$ source ll_env/bin/activate
(ll_env)learning_log$

این دستور اسکریپت activate در ll_env/bin را اجرا می‌کند. زمانی که محیط فعّال باشد، نام آن را داخل پرانتز خواهید دید، مانند آن‌چه در بالا می‌بینید؛ سپس می‌توانید بسته‌ها را در آن نصب کنید و از بسته‌هایی که قبلاً نصب کرده‌اید استفاده کنید. بسته‌هایی که در ll_env نصب می‌کنید تنها زمانی در دسترس‌اند که محیط فعّال باشد.

نکته
اگر از ویندوز استفاده می‌کنید برای فعّال‌سازی محیط مجازی از دستور ll_env\Script\activate استفاده کنید (بدون کلمه‌ی source). اگر از PowerShell استفاده می‌کنید شاید نیاز باشد که Activate را با حرف اوّل بزرگ بنویسید.

برای توقّف کار با یک محیط مجازی deactivate را وارد کنید:

1
2
(ll_env)learning_log$ deactivate
learning_log$

همچنین اگر ترمینالی را که محیط مجازی در آن اجرا می‌شود ببندید، محیط غیرفعّال می‌شود.

نصب جانگو

پس از فعّال شدن محیط مجازی موارد زیر را برای نصب جانگو وارد کنید:

1
2
3
4
5
6
(ll_env)learning_log$ pip install django
Collecting django
--snip--
Installing collected packages: pytz, django
Successfully installed django-2.2.0 pytz-2018.9 sqlparse-0.2.4
(ll_env)learning_log$

چون اکنون در یک محیط مجازی کار می‌کنیم، که محیطی خودمتّکی است، این دستور در تمام سیستم‌ها یکسان خواهد بود. نیازی به استفاده از پرچم –user نیست و لازم نیست فرمان‌های طولانی‌تری مانند python -m pip install package_name استفاده کنید.

در خاطر داشته باشید که جانگو تنها در صورت فعّال بودن محیط ll_env در دسترس خواهد بود.

نکته
جانگو هر هشت ماه یک بار نسخه‌ی جدیدی منتشر می‌کند پس ممکن است هنگام نصب آن نسخه‌ی جدیدتری ببینید. این پروژه همان‌گونه که اینجا نوشته شده به احتمال زیاد حتّی در نسخه‌های جدید جانگو هم کار خواهد کرد. اگر می‌خواهید مطمئن شوید که از نسخه‌ی مشابه اینجا استفاده می‌کنید از دستور pip install django==2.2.* استفاده کنید. این دستور آخرین نسخه‌ی جانگوی 2.2 را نصب می‌کند. اگر با نسخه‌ای که استفاده می‌کنید مشکلی دارید منابع آنلاین کتاب را در https://nostarch.com/pythoncrashcourse2e ببینید.

ساختن یک پروژه در جانگو

بدون ترک کردن محیط مجازی فعّال (حواستان به عبارت ll_env داخل پرانتز در اعلان ترمینال باشد) دستورهای زیر را برای ساختن یک پروژه‌ی جدید وارد کنید:

1
2
3
4
5
(ll_env)learning_log$ django-admin startproject learning_log .
(ll_env)learning_log$ ls
learning_log  ll_env  manage.py
(ll_env)learning_log$ ls learning_log
__init__.py  settings.py  urls.py  wsgi.py

دستور اوّل از جانگو می‌خواهد که پروژه‌ی جدیدی به نام learning_log بسازد. نقطه در انتهای دستور پوشه‌های پروژه‌ی جدید را با ساختاری می‌سازد که استقرار برنامه را در سرور پس از پایان توسعه‌ی آن آسان می‌کند.

نکته
گذاشتن این نقطه را فراموش نکنید وگرنه هنگام استقرار برنامه به برخی مشکلات در تنظیمات برخواهید خورد. اگر نقطه را فراموش کردید فایل‌ها و پوشه‌های ایجادشده را پاک کنید (به جز ll_env) و سپس دستور را دوباره اجرا کنید.

اجرای دستور ls در خروجی نشان می‌دهد که جانگو پوشه‌ای جدید به نام learning_log ساخته است. یک فایل manage.py هم ساخته شده که برنامه‌ای کوتاه است که دستورها را می‌گیرد و آن‌ها را بخش‌های مرتبط جانگو می‌دهد تا آن‌ها را اجرا کند. از این دستورها برای مدیریّت وظیفه‌ها مانند کار کردن با پایگاه‌های داده و اجرای سرورها استفاده خواهیم کرد.

پوشه‌ی learning_log چهار فایل را شامل می‌شود؛ که مهم‌ترین آن‌ها settings.py، urls.py و wsgi.py است. فایل settings.py نحوه‌ی تعامل جانگو با سیستم شما را کنترل و پروژه‌ی شما را مدیریّت می‌کند. همگام با تحوّل پروژه برخی از این تنظیمات را تغییر داده و برخی تنظیمات خود را نیز اضافه خواهیم کرد. فایل urls.py به جانگو می‌گوید که در پاسخ به درخواست‌های مرورگر چه صفحاتی بسازید. فایل wsgi.py به جانگو کمک می‌کند که فایل‌هایی را که ایجاد می‌کند ارائه کند. نام این فایل سرواژه‌ی web server gateway interface است.

ساختن پایگاه داده

جانگو بیشتر اطّلاعات مربوط به پروژه را در یک پایگاه داده نگه می‌دارد پس در گام بعدی لازم است که پایگاه داده‌ای بسازیم تا جانگو با آن کار کند. دستور زیر را (همچنان در محیط فعّال) وارد کنید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(ll_env)learning_log$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  --snip--
  Applying sessions.0001_initial... OK
(ll_env)learning_log$ ls
db.sqlite3  learning_log  ll_env  manage.py

هر گاه یک پایگاه داده را تغییر می‌دهیم از اصطلاح 147 انتقال پایگاه داده استفاده می‌کنیم. اوّلین اجرای دستور migrate از جانگو می‌خواهد که از تطابق پایگاه داده با وضعیّت فعلی پروژه اطمینان حاصل کند. اوّلین باری که این دستور را در یک پروژه‌ی جدید با SQLite (به زودی به آن خواهیم پرداخت) اجرا می‌کنید جانگو یک پایگاه داده‌ی جدید برای ما می‌سازد. جانگو اطّلاع می‌دهد که پایگاه داده را برای اطّلاعات مورد نیاز جهت مدیریّت وظایفه‌های مدیریّت و احراز هویّت آماده خواهد کرد.

اجرای دستور ls نشان می‌دهد که جانگو فایل دیگری به نام db.sqlite3 ساخته است. SQLite یک پایگاه داده است که تنها در یک فایل خلاصه می‌شود و برای نوشتن برنامه‌های ساده ایده‌ال است چون نیاز نیست بیش از حد به جزئیات مدیریّت پایگاه داده بپردازید.

نکته
برای اجرای دستورهای manage.py در یک محیط مجازی فعّال از فرمان python استفاده کنید حتّی اگر برای اجرای دیگر برنامه‌ها از python3 بهره می‌گیرید. در یک محیط مجازی فرمان python به نسخه‌ی پایتونی اشاره می‌کند که محیط مجازی را ساخته است.

مشاهده‌ی پروژه

اجازه دهید از برپایی درست پروژه مطمئن شویم. دستور runserver را مانند زیر اجرا کنید تا وضعیّت فعلی پروژه را ببینید:

1
2
3
4
5
6
7
8
9
(ll_env)learning_log$ python manage.py runserver
Watchman unavailable: pywatchman not installed.
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
February 18, 2019 - 16:26:07
Django version 2.2.0, using settings 'learning_log.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

جانگو باید سروری به نام سرور توسعه را راه بیاندا148 زد تا شما بتوانید پروژه را در سیستم خود ببینید و از صحّت عملکرد آن مطمئن شوید. زمانی که با وارد کردن یک URL در یک مرورگر صفحه‌ای را درخواست می‌کنید سرور جانگو با ساختن صفحه‌ی متناسب به آن پاسخ می‌دهد و آن را به مرورگر می‌فرستد.

جانگو بررسی می‌کند تا مطمئن شود پروژه به درستی برپا شده؛ نسخه‌ی جانگو و نام فایل تنظیمات مورد استفاده را گزارش می‌150 149 کند؛ URLای را که پروژه در آن ارائه می‌شود گزارش می‌کند. آدرس http://127.0.0.1:8000/ نشان می‌دهد که به درخواست‌های روی درگاه ۸۰۰۰ در رایانه‌ی شما، که میزبان‌محلّی نامیده می‌شود، پاسخ می‌دهد. عبارت میزبان محلّی به سروری اشاره می‌کند که تنها به درخواست‌های روی سیستم شما پاسخ می‌دهد؛ این سرور به هیچ کس دیگری اجازه نمی‌دهد که صفحه‌های در حال توسعه‌ی شما را ببیند.

یک مرورگر وب باز کنید و آدرس http://localhost:8000/ یا اگر کار نکرد، http://127.0.0.1:8000/ را وارد کنید. باید صفحه‌ای ببینید که جانگو می‌سازد تا نشان دهد تا اینجا همه چیز به خوبی پیش رفته است. فعلاً سرور را در حال اجرا نگه دارید امّا هرگاه خواستید آن را متوقّف کنید CTRL+C را در ترمینالی که فرمان runserver صادر شده اجرا کنید.

نکته
اگر پیام خطایی مبنی بر اشغال بودن درگاه دریافت کردید با وارد کردن دستور python manage.py runserver 8001 از جانگو بخواهید که از درگاه دیگری استفاده کنید و شماره‌ی درگاه را افزایش دهید تا یک درگاه خالی پیدا کنید.

خودآزمایی

۱۸-۱- پروژه‌های جدید: برای این که درک بهتری از جانگو پیدا کنید چند پروژه‌های خالی بسازید و به فایل‌هایی که می‌سازد توجّه کنید. پوشه‌ی جدید با نامی ساده مانند snap_gram یا insta_chat (خارج از پوشه‌ی learning_log) بسازید، با یک ترمینال وارد آن شوید و یک محیط مجازی بسازید. جانگو را نصب و فرمان django-admin.py startproject snap_gram . را اجرا کنید. (مطمئن شوید که نقطه را در پایان دستور می‌آورید.)

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

3 - آغاز کردن یک برنامه

یک پروژه‌ی جانگو به صورت گروهی از برنامه‌های کاربردی مجزّا ساختار یافته است که با هم کار می‌کنند تا پروژه مانند یک واحد کلّی عمل کند. فعلاً فقط یک برنامه‌ی کاربردی می‌سازیم تا بیشتر کار پروژه‌ی ما را انجام دهد. در فصل ۱۹ یک برنامه‌ی دیگر اضافه می‌کنیم تا حساب‌های کاربری را مدیریّت کند.

شما باید اجازه دهید که سرور توسعه‌ای که پیش‌تر در پنجره‌ی ترمینال باز کرده‌اید به کار خود ادامه دهد. یک برگه یا پنجره‌ی ترمینال جدید باز کنید و به پوشه‌ای بروید که manage.py در آن است. محیط مجازی را فعّال کنید و فرمان startapp را اجرا کنید:

1
2
3
4
5
6
learning_log$ source ll_env/bin/activate
(ll_env)learning_log$ python manage.py startapp learning_logs
(ll_env)learning_log$ ls
db.sqlite3  learning_log  learning_logs  ll_env  manage.py
(ll_env)learning_log$ ls learning_logs/
__init__.py  admin.py  apps.py  migrations  models.py  tests.py  views.py

دستور startapp از جانگو می‌خواهد که زیرساخت‌های لازم را برای ساختن یک برنامه فراهم آورد. اگر اکنون به پوشه‌ی پروژه نگاه کنید پوشه‌ای جدید به نام learning_logs خواهید دید. آن پوشه را باز کنید تا ببینید جانگو چه چیزهایی در آن ساخته است. مهم‌ترین فایل‌ها عبارت‌اند از models.py، admin.py و views.py. از models.py برای تعریف کردن داده‌هایی که می‌خواهیم در برنامه مدیریّت کنیم استفاده می‌کنیم. به دو فایل admin.py و views.py کمی بعد نگاهی می‌اندازیم.

تعریف کردن مدل‌ها

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

فایل models.py را باز کنید و به محتویّات فعلی آن نگاهی بیندازید:

1
2
3
from django.db import models

# Create your models here.

ماژولی به نام models برای ما وارد شده است و از ما دعوت شده که مدل‌های خود را بسازیم. یک مدل به جانگو می‌گوید که چگونه با داده‌های ذخیره‌شده در برنامه کار کند. از منظر کدنویسی مدل تنها یک کلاس است که درست مانند همه‌ی کلاس‌هایی که مورد بحث قرار دادیم، مشخّصه‌ها و متدهایی دارد. برای موضوعاتی که کاربران ذخیره خواهند کرد چنین مدلی داریم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.db import models

class Topic(models.Model):
    """A topic the user is learning about."""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """Return a string representation of the model."""
        return self.text

کلاسی به نام Topic ساخته‌ای که از Model ارث می‌برد—کلاس والدی که در جانگو آورده شده و قابلیّت‌های ابتدایی یک مدل را تعریف می‌کند. به کلاس Topic دو مشخّصه‌ی text و date_added را اضافه می‌کنیم.

مشخّصه‌ی text یک نوع CharField است— بخشی داده که از حرف‌ها یا متن تشکیل شده است. از CharField زمانی استفاده می‌کنید که می‌خواهید متن‌های کوچکی مانند نام، عنوان یا شهر را ذخیره کنید. زمانی که یک مشخّصه‌ی CharField تعریف می‌کنیم باید به جانگو بگوییم که چه‌قدر فضا در پایگاه داده اشغال خواهد کرد. اینجا ما max_length را ۲۰۰ حرف تعریف کرده‌ایم که برای نگه‌داری نام بیشتر موضوعات کافی است.

مشخّصه‌ی date_added از نوع DateTimeField است— داده‌ای که تاریخ و ساعتی را ضبط خواهد کرد. نشان‌وند auto_now_add=True را به آن می‌دهیم تا هر گاه کاربر موضوع جدیدی ایجاد کرد جانگو به طور خودکار این مشخّصه را برابر با تاریخ و زمان فعلی قرار دهد.

نکته
برای دیدن انواع مختلف فیلدهایی که می‌توانید در یک مدل استفاده کنید، مرجع فیلدِ مدل جانگو را در آدرس https://docs.djangoproject.com/en/2.2/ref/models/fields ببینید. همین الان به این اطّلاعات نیازی ندارید امّا این مرجع هنگامی که برنامه‌های خود را توسعه می‌دهید بسیار مفید خواهد بود.

به جانگو می‌گوییم که به طور پیش‌فرض کدام مشخّصه را درباره‌ی یک موضوع نشان دهد. جانگو یک متد __str__() را برای نمایش ساده‌ی یک مدل فرامی‌خواند. اینجا یک متد __str__() نوشته‌ایم که رشته‌ی ذخیره‌شده در مشخّصه‌ی text را برمی‌گرداند.

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

برای استفاده از مدل‌های خود باید به جانگو بگوییم که برنامه‌ی ما را در پروژه‌ی کلّی بگنجاند. فایل settings.py را (در پوشه‌ی learning_log/learning_log) باز کنید؛ بخشی را خواهید دید که به جانگو می‌گوید چه برنامه‌های نصب شده‌اند و با هم در پروژه کار می‌کنند:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
--snip--
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
--snip--

برنامه‌ی خود را با تغییر دادن INSTALLED_APPS به فهرست اضافه می‌کنیم تا به این شکل درآید:

1
2
3
4
5
6
7
8
9
--snip--
INSTALLED_APPS = [
    # My apps
    'learning_logs',
    # Default django apps.
    'django.contrib.admin',
    --snip--
]
--snip--

گروه‌بندی برنامه‌ها با هم در یک پروژه کمک می‌کند که همزمان با بزرگ شدن پروژه و در برگرفتن برنامه‌های بیشتر، آن‌ها را پیگیری کنید. اینجا بخشی به نام My Apps می‌سازیم که فعلاً تنها شامل learning_logs است. قرار دادن برنامه‌ی خود قبل از برنامه‌های پیش‌فرض زمانی مهم است که بخواهید هر کدام از رفتارهای این برنامه‌های پیش‌فرض را با رفتار دلخواه خود جایگزین کنید.

در گام بعدی باید به جانگو بگوییم که پایگاه داده را تغییر دهد تا بتواند اطّلاعات مرتبط با مدل Topic را ذخیره کند. در ترمینال دستور زیر را اجرا کنید:

1
2
3
4
5
(ll_env)learning_log$ python manage.py makemigrations learning_logs
Migrations for 'learning_logs':
  learning_logs/migrations/0001_initial.py
    - Create model Topic
(ll_env)learning_log$

دستور makemigrations به جانگو می‌فهماند که چگونه پایگاه‌داده را برای ذخیره‌سازی داده‌های مرتبط با مدل‌های تعریف‌شده تغییر دهد. خروجی اینجا نشان می‌دهد که جانگو یک فایل جابه‌جایی به نام 0001_initial.py ساخته است که جدولی برای مدل Topic در پایگاه داده خواهد ساخت.

اکنون این انتقال را اعمال می‌کنیم و جانگو پایگاه داده را برای ما تغییر می‌دهد:

1
2
3
4
5
(ll_env)learning_log$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  Applying learning_logs.0001_initial... OK

بیشتر خروجی این دستور عیناً مشابه اوّلین اجرای آن است. خطّی که باید آن را بررسی کنیم جایی است که جانگو تایید می‌کند انتقال learning_logs به درستی انجام شده است.

هرگاه بخواهیم داده‌هایی را تغییر دهیم که Learning Log مدیریّت می‌کند، باید این سه گام را پی بگیریم: تغییر دادن models.py، فراخوانی makemigrations برای learning_logs و درخواست از جانگو برای migrate کردن پروژه.

4 - سایت مدیریّت جانگو

جانگو کار کردن با مدل‌ها را از طریق سایت مدیرّیت خود ساده می‌کند که تنها مدیران سایت از آن استفاده می‌کنند نه کاربران عمومی. در این بخش یک سایت مدیریّت برپا می‌کنیم و از آن برای افزودن چند موضوع از طریق مدل Topic استفاده می‌کنیم.

برپایی یک ابرکاربر

جانگو به شما امکان می‌دهد که یک ابرکاربر بسازید؛152 151 کاربری که از تمام امتیازات موجود در سایت برخوردار است. امتیازات یک کاربر اعمالی را که کاربر می‌تواند انجام دهد کنترل می‌کند.

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

برای ساختن یک ابرکاربر در جانگو دستور زیر را وارد کنید و به اعلان‌های آن پاسخ دهید:

1
2
3
4
5
6
7
(ll_env)learning_log$ python manage.py createsuperuser
Username (leave blank to use 'eric'): ll_admin
Email address:
Password:
Password (again):
Superuser created successfully.
(ll_env)learning_log$

زمانی که دستور createsuperuser را صادر می‌کنید جانگو از شما نام کاربری مورد نظرتان را برای ابرکاربر می‌پرسد. اینجا من از ll_admin استفاده می‌کنم امّا شما می‌توانید هر نامی که خواستید وارد کنید. می‌توانید در صورت تمایل یک آدرس ایمیل هم وارد کنید یا این اعلان را خالی بگذارید. باید گذرواژه‌ی خود را دو بار وارد کنید.

نکته
برخی اطّلاعات حسّاس از مدیران سایت مخفی‌اند. برای مثال جانگو گذرواژه را153 به صورتی که شما وارد می‌کنید ذخیره نمی‌کند؛ بلکه آن را به صورت رشته‌ای که از این گذرواژه به دست می‌آید و درهم‌ساخته یا هَش نامیده می‌شود، ضبط می‌کند. هر بار که شما گذرواژه‌ای وارد می‌کنید جانگو آن را در هم می‌ریزد و سپس با هَش ذخیره‌شده مقایسه می‌کند. اگر این دو منطبق باشند هویّت شما احراز می‌شود. با الزام انطباق این دو هَش، اگر مهاجمی به پایگاه داده‌ی سایت شما دسترسی پیدا کند، می‌تواند هش‌های ذخیره‌شده را بخواند نه گذرواژه‌ها را. اگر سایتی درست بر پا شود بازیابی گذرواژه‌های اصلی از هش‌ها تقریباً غیر ممکن است.

ثبت کردن یک مدل با سایت مدیر

جانگو چند مدل را به طور خودکار دربرمی‌گیرد، مانند User و Group، امّا مدل‌هایی که خودمان ساخته‌ایم باید به صورت دستی اضافه شوند.

زمانی که برنامه‌ی learning_logs را شروع کردیم جانگو یک فایل admin.py در همان پوشه‌ی models.py ایجاد کرد. آن را باز کنید:

1
2
3
from django.contrib import admin

# Register your models here.

برای ثبت Topic از طریق سایت مدیرّیت کد زیر را وارد کنید:

1
2
3
4
from django.contrib import admin
from .models import Topic

admin.site.register(Topic)

در این کد ابتدا مدلی، Topic، را وارد می‌کنیم که می‌خواهیم آن را ثبت کنیم. نقطه‌ی جلوی models به جانگو می‌گوید که در همان پوشه‌ی حاوی admin.py به دنبال models.py بگردد. کد admin.site.register() از جانگو می‌خواهد که مدل ما را از طریق سایت مدیر مدیریّت کند.

اکنون از حساب کاربری ابرکاربر برای دسترسی به سایت مدیر استفاده کنید. به آدرس https://localhost:8000/admin/ بروید و نام کاربری و گذرواژه‌ی ابرکاربری را که ساخته‌اید وارد کنید. باید صفحه‌ای ببینید که به شما اجازه می‌دهد که کاربران و گروه‌های جدید را ایجاد کرده یا قبلی‌ها را تغییر دهید. همچنین می‌توانید با مدل Topic که کمی پیش‌تر تعریف کرده‌اید کار کنید.

نکته
اگر در مرورگر خود پیامی مبنی بر در دسترسی نبودن صفحه‌ی وب دیدید مطمئن شوید که سرور جانگو همچنان در پنجره‌ی ترمینال اجرا می‌شود. اگر چنین نیست یک محیط مجازی فعّال کنید و فرمان python manage.py runserver را مجدداً صادر کنید. اگر هر جایی در فرآیند توسعه در مشاهده‌ی پروژه‌ی خود دچار مشکل شدید، اوّلین گام مناسب برای رفع اشکال بستن تمام ترمینال‌ها و صدور مجدّد فرمان runserver است.

افزودن موضوعات

اکنون که Topic از طریق سایت مدیر ثبت شده بیایید اوّلین موضوع خود را اضافه کنیم. روی Topics کلیک کنید تا به صفحه‌ی موضوعات بروید که تقریباً خالی است زیرا هنوز هیچ موضوعی برای مدیریّت نداریم. روی Add Topic کلیک کنید تا فرمی برای افزودن موضوع جدید ظاهر شود. Chess را در اوّلین خانه وارد کنید و Save را بزنید. به صفحه‌ی مدیریّت موضوعات برگردانده می‌شوید و موضوعی را که هم‌اکنون اضافه کردید می‌بینید.

موضوع دومی را هم اضافه می‌کنیم تا داده‌ی بیشتری برای کار کردن داشته باشیم. دوباره روی Add Topic کلیک کنید و این بار Rock Climbing را وارد کنید. Save را فشار دهید تا دوباره به صفحه‌ی اصلی موضوعات برگردید. حال شما شطرنج و صخره‌نوردی را در فهرست خود دارید.

تعریف کردن مدلی برای مطلب‌ها

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

این کد مدل Entry است. آن را در فایل models.py قرار دهید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from django.db import models

class Topic(models.Model):
    --snip--

class Entry(models.Model):
    """Something specific learned about a topic."""
    topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
    text = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = 'entries'

    def __str__(self):
        """Return a string representation of the model."""
        return f"{self.text[:50]}..."

کلاس Entry مانند Topic از کلاس Model جانگو ارث می‌156 155 برد. اوّلین مشخّصه، topic، نمونه‌ای از ForeignKey است. یک کلید خارجی اصطلاحی در پایگاه‌های داده است و ارجاعی به یک رکورد دیگر در پایگاه داده به شمار می‌آید. به هر موضوع هنگام ساخته شدن، یک کلید یا ID نسبت داده می‌شود. زمانی که جانگو می‌خواهد بین دو داده ارتباط برقرار کند از کلید‌هایی استفاده می‌کند که به هر کدام نسبت داده شده است. به زودی از این ارتباط‌ها برای دریافت تمام مطالب مرتبط با یک موضوع خاص استفاده خواهیم کرد. نشان‌وند on_delete=models.CASCADE به جانگو می‌گوید که اگر موضوعی حذف شد، تمام موضوعات مرتبط با آن را هم حذف کن. این روش به نام حذف آبشاری شناخته می‌شود.

مشخّصه‌ی بعدی text نامیده می‌شود که نمونه‌ای از TextField است. این فیلد نیازی به محدودیّت طول ندارد زیرا قصد نداریم اندازه‌ی مطالب را محدود کنیم. مشخّصه‌ی date_added به ما امکان می‌دهد که مطالب را به ترتیبی که ایجاد شده‌اند نشان دهیم و کنار هر کدام یک برچسب زمانی قرار دهید.

کلاس Meta را داخل کلاس Entry قرار می‌دهیم. این کلاس اطّلاعات اضافی را در مورد مدیریّت یک مدل در برمی‌گیرد؛ اینجا به ما امکان می‌دهد که مشخّصه‌ای ویژه تنظیم کنیم تا به جانگو بگوییم که هرگاه به بیش از یک موضوع اشاره کرد، از Entries استفاده کند. بدون این جانگو به چند موضوع Entrys اطلاق می‌کند.

متد __str__() برای جانگو مشخّص می‌کند که چه هنگام نمایش هر موضوع چه چیزی را نشان دهد. از آن‌جایی که طول متن می‌تواند خیلی زیاد باشد از جانگو می‌خواهیم که تنها ۵۰ حرف آن را نمایش دهد. یک سه‌نقطه نیز اضافه می‌کنیم که شفّاف کنیم همیشه تمام مطلب را نمایش نمی‌دهیم.

5 - انتقال مدل Entry

چون مدل جدیدی اضافه کرده‌ایم باید پایگاه داده را دوباره تغییر دهیم. به تدریج با این فرآیند آشنا خواهید شد: ابتدا models.py را تغییر می‌دهید، سپس فرمان python manage.py makemigrations app_name را صادر و دستور python manage.py migrate را اجرا می‌کنید.

پایگاه داده را انتقال دهید و خروجی را با وارد کردن فرمان‌های زیر بررسی کنید:

1
2
3
4
5
6
7
8
(ll_env)learning_log$ python manage.py makemigrations learning_logs
Migrations for 'learning_logs':
  learning_logs/migrations/0002_entry.py
    - Create model Entry
(ll_env)learning_log$ python manage.py migrate
Operations to perform:
  --snip--
  Applying learning_logs.0002_entry... OK

فایل انتقال جدیدی به نام 0002_entry.py تولید می‌شود که به جانگو می‌گوید چگونه پایگاه داده را برای ذخیره‌سازی اطّلاعات مربوط به مدل Entry تغییر دهد. هنگام صدور فرمان migrate می‌بینیم که جانگو انتقال را انجام داده و همه چیز درست است.

ثبت Entry با سایت مدیر

باید مدل Entry را نیز ثبت کنیم. اکنون باید فایل admin.py اینگونه به نظر بیاید:

1
2
3
4
5
from django.contrib import admin
from .models import Topic, Entry

admin.site.register(Topic)
admin.site.register(Entry)

به http://localhost/admin/ بروید موضوعات فهرست شده ذیل Learning_Log را ببینید. روی پیوند Add برای موضوعات یا روی Entries کلیک کنید و سپس Add entry را بزنید. اینجا باید یک لیست پایین‌افتادنی برای انتخاب موضوع مطلب خود و یک خانه برای وارد کردن متن خود ببینید. Chess را از لیست پایین‌افتادنی انتخاب کنید و یک موضوع اضافه کنید. این اوّلین مطلبی است که من ساخته‌ام:

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

البته این‌ها تنها چند راهنماست. مهم است که یاد بگیرید کی از آن‌ها پیروی کنید و کی به این توصیه‌ها عمل نکنید.

زمانی که روی Save کلیک می‌کنید به صفحه‌ی اصلی مدیریّت مطالب برمی‌گردید. این فایده‌ی استفاده از text[:50] را برای نمایش رشته‌ای هر مطلب می‌بینید: اگر به جای کلّ مطلب تنها بخشی از آن را ببینید کار کردن با چند مطلب در رابط مدیریّتی بسیار ساده‌تر خواهد بود.

مطلب دومی در مورد شطرنج و یک مطلب در رابطه با صخره‌نوردی اضافه کنید تا کمی داده‌ی ابتدایی داشته باشیم. این دومین مطلب در مورد شطرنج است:

در مرحله‌ی آغازین بازی مهم است که اسب‌ها و فیل‌های خود را بیرون بیاورید. این مهره‌ها قدرتمندند و به اندازه‌ی کافی تحرّک‌پذیرند تا در حرکت‌های ابتدایی بازی نقش مهمّی بازی کنند.

و این اوّلین مطلب درباره‌ی صخره‌نوردی است:

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

همچنان که به توسعه‌ی Learning Log ادامه می‌دهیم این سه مطلب حداقل‌هایی برای کار کردن فراهم می‌آورند.

پوسته‌ی جانگو

با این چند داده‌ای که وارد کردیم می‌توانیم داده‌ها157 را از طریق یک نشست تعاملی ترمینال با برنامه‌نویسی بررسی کنیم. این محیط تعاملی پوسته‌ی جانگو نامیده می‌شود و محیط فوق‌العاده‌ای برای آزمودن و اشکال‌زدایی پروژه‌ی شماست. این مثالی از نشست تعاملی پوسته است:

1
2
3
4
(ll_env)learning_log$ python manage.py shell
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>

فرمان python manage.py shell که در یک محیط مجازی فعّال اجرا می‌شود، یک مفسّر پایتون فراهم می‌آورد که می‌توانید از آن برای بررسی داده‌های ذخیره‌شده در پایگاه داده‌ی پروژه‌ی خود استفاده کنید. اینجا مدل Topic را از ماژول learning_logs.models وارد کرده‌ایم. سپس از متد Topic.objects.all() برای گرفتن تمام نمونه‌های مدل Topic استفاده می‌کنیم؛ لیستی که برگردانده می‌شود یک queryset نامیده می‌شود.

درست مثل یک لیست می‌توانید در یک queryset هم حلقه بزنید. اینجا روش فهمیدن شماره‌ای را که به هر عنوان نسبت داده شده می‌بینیم:

1
2
3
4
5
6
>>> topics = Topic.objects.all()
>>> for topic in topics:
...     print(topic.id, topic)
...
1 Chess
2 Rock Climbing

این queryset را در topics ذخیره می‌کنیم و سپس مشخّصه‌ی id هر موضوع و بیان رشته‌ای آن را چاپ می‌کنیم. می‌بینیم که موضوع شطرنج شماره‌ی ۱ و موضوع صخره‌نوردی شماره‌ی ۲ را گرفته است.

اگر شماره‌ی یک شیء خاص را بدانید می‌توانید از متد Topic.objects.get() برای دریافت آن و بررسی هرکدام از مشخّصه‌های آن استفاده کرد. بیایید نگاهی به مقدارهای text و date_added مربوط به Chess بیندازیم:

1
2
3
4
5
>>> t = Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2019, 2, 19, 1, 55, 31, 98500, tzinfo=<UTC>)

علاوه بر این‌ها می‌توانیم مطالب مرتبط با یک موضوع خاص را هم ببینیم. پیش‌تر مشخّصه‌ی topic برای مدل Entry تعریف کردیم. این یک ForeignKey است، رابطه‌ای بین یک موضوع و یک مطلب. جانگو از این ارتباط برای گرفتن هر مطلب مرتبط با یک موضوع استفاده می‌کند؛ مانند زیر:

1
2
3
>>> t.entry_set.all()
<QuerySet [<Entry: The opening is the first part of the game, roughly...>,
<Entry: In the opening phase of the game, it's important t...>]>

برای گرفتن داده‌ها از طریق رابطه‌ی کلید خارجی می‌توانید از نام مدل مربوطه با حروف کوچک و به دنبال آن یک زیرخط و کلمه‌ی set استفاده کنید. برای مثال فرض کنید که دو مدل Pizza و Topping را دارید و Topping از طریق یک کلید خارجی با Pizza مرتبط است. اگر نام شیء شما my_pizza باشد، که نماینده‌ی یک پیتزاست، می‌توانید تمام مخلّفات این پیتزا را با استفاده از my_pizza.topping_set.all() دریافت کنید.

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

نکته
هر بار که مدل‌ها را تغییر می‌دهید برای دیدن اثر تغییراتی که اعمال کرده‌اید باید پوسته را از نو اجرا کنید. برای خروج از نشست پوسته CTRL-D را بزنید؛ در ویندوز Ctrl-Z و سپس Enter را بزنید.

خودآزمایی

۱۸-۲: مطالب کوتاه: در حال حاضر هنگامی که جانگو مطالب را در سایت مدیر یا در پوسته نشان می‌دهد، متد __str__() در مدل Entry سه‌‌نقطه را به تمام مطلب‌ها اضافه می‌کند. یک عبارت if به این متد اضافه کنید تا تنها در صورتی سه‌نقطه را اضافه کند که طول متن بیشتر از ۵۰ حرف باشد. از سایت مدیر برای اضافه کردن یک مطالب کوتاه‌تر از ۵۰ حرف استفاده کنید و بررسی کنید که سه‌نقطه هنگام نمایش وجود نداشته باشد.

۱۸-۳: API جانگو: زمانی که برای دسترسی به داده‌های158 پروژه‌ی خود کدی می‌نویسید، شما در واقع در حال نوشتن یک عبارت پرس و جو هستید. به مستندات مربوط به پرس و جو در آدرس https://docs.djangoproject.com/en/2.2/topics/db/queries/ نگاهی بیندازید. بیشتر چیزی که می‌بینید برای شما تازگی دارد امّا هنگام شروع کار بر پروژه‌های خود بسیار مفید خواهند بود.

۱۸-۴: پیتزافروشی: پروژه‌ای جدید به نام pizzeria با برنامه‌ای به نام pizzas آغاز کنید. یک مدل Pizza با فیلدی به نام name تعریف کنید که نام پیتزاها را نگه می‌دارد، مانند Hawaiian و Meat Lovers. مدلی به نام Topping با فیلدهای pizza و name تعریف کنید. فیلد pizza باید یک کلید خارجی به Pizza باشد و نام باید مقدارهای مربوط به مخلّفات مانند pineapple، Canadian bacon و sausage را ذخیره کند.

هر دو مدل را از طریق سایت مدیر ثبت کنید و از این سایت برای وارد کردن نام چند پیتزا و مخلّفات آن استفاده کنید. از پوسته کمک بگیرید تا داده‌های واردشده را ببینید.

6 - ساختن صفحه‌ها: صفحه‌ی خانه‌ی Learning Log

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

هر URL با یک نمای خاص مرتبط می‌شود—تابع نما داده161 160 ‌های مورد نیاز برای تولید آن صفحه را دریافت و پردازش می‌کند. تابع نما اغلب صفحه را به کمک یک قالب شکل می‌دهد که ساختار کلّی صفحه را دربرمی‌گیرد. برای دیدن این روش کار بیایید برای Learning Log یک صفحه‌ی خانه بسازیم. برای این صفحه URLای تعیین می‌کنیم، تابع نمای آن را می‌نویسیم و یک قالب ساده می‌سازیم.

فعلاً چون فقط قصد داریم مطمئن شویم که Learning Log آن‌گونه که انتظار داریم کار می‌کند، یک صفحه‌ی ساده می‌سازیم. شکل دادن به یک برنامه‌ی وبِ در حال کار پس از ساخته‌شدن کاری جذّاب است امّا برنامه‌ای که به زیبا به نظر برسد امّا کار نکند بی‌فایده است. صفحه‌ی خانه فعلاً فقط یک عنوان و یک شرح مختصر را نمایش می‌دهد.

نگاشتن یک URL

کاربران با وارد کردن URLها در مرورگر یا کلیک کردن روی پیوندها صفحه‌ها را درخواست می‌کنند پس باید تصمیم بگیریم که به چه URLهایی نیاز داریم. URL صفحه‌ی خانه اوّلین مورد است: URL پایه است که افراد برای دسترسی به پروژه استفاده می‌کنند. در حال حاضر URL پایه http://localhost:8000/ است که سایت پیش‌فرض جانگو را برمی‌گرداند و به ما می‌گوید که پروژه به درستی برپا شده است. این صفحه را با نگاشت URL پایه به صفحه‌ی خانه‌ی Learning Log عوض می‌کنیم.

در پوشه‌ی اصلی پروژه‌ی learning_log فایل urls.py را باز کنید. چیزی که می‌بینید این است:

1
2
3
4
5
6
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

دو خطّ اوّل یک ماژول و یک تابع برای مدیریّت URLهای سایت مدیریّت وارد می‌کند. در بدنه‌ی فایل متغیّر urlpatterns تعریف می‌شود. در این فایل urls.py که کل پروژه را نمایندگی می‌کند، متغیّر urlpatterns مجموعه‌ای از URLهای برنامه‌های داخل پروژه را در برمی‌گیرد. کد در ماژول admin.site.urls را شامل می‌شود که تمام URLهایی را تعریف می‌کند که می‌توان از سایت مدیر درخواست کرد.

ما باید URLهای مربوط به learning_log را هم اضافه کنیم پس:

1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('learning_logs.urls')),
]

خطّی اضافه کرده‌ایم تا ماژول learning_logs.urls را اضافه کنیم. فایل urls.py پیش‌فرض در پوشه‌ی learning_log قرار دارد؛ اکنون باید یک فایل urls.py دیگر در پوشه‌ی learning_logs بسازیم. یک فایل پایتون جدید ساخته و آن را در learning_logs به نام urls.py ذخیره کنید و کد زیر را در آن وارد کنید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
"""Defines URL patterns for learning_logs."""
from django.urls import path
from . import views

app_name = 'learning_logs'

urlpatterns = [
    # Home page
    path('', views.index, name='index'),
]

یک docstring به ابتدای فایل اضافه می‌کنیم تا مشخّص شود که روی کد urls.py در حال کاریم. سپس تابع path را وارد می‌کنیم که برای نگاشت URLها به نماها مورد نیاز است. ماژول views را هم وارد می‌کنیم؛ نقطه به پایتون می‌گوید که ماژول views.py را از همان پوشه‌ی ماژول urls.py فعلی وارد کند. متغیّر app_name به جانگو کمک می‌کند که این فایل urls.py را از فایل‌های هم‌نام در دیگر برنامه‌های پروژه تشخیص دهد. متغیّر urlpatterns در این ماژول لیستی از صفحه‌های جداگانه است که می‌تواند از طریق برنامه‌ی learning_logs درخواست شود.

الگوی URL در حقیقت فراخوانی تابع path() است که سه نشان‌وند می‌پذیرد. اوّلین نشان‌وند رشته‌ای است که به جانگو کمک می‌کند درخواست فعلی را به درستی مسیریابی کند. جانگو URL درخواستی را گرفته و سعی می‌کند که آن را به یک نما متّصل کند. این کار با جست‌و‌جوی تمام الگوهای تعریف‌شده تا یافتن موردی که به درخواست فعلی می‌خورد انجام می‌شود. جانگو URL پایه‌ی پروژه (https://localhost:8000/) را در نظر نمی‌گیرد پس رشته‌ی خالی (’’) متناظر با URL پایه است. هیچ URL دیگری با این الگو تطبیق نخواهد یافت و اگر جانگو هیچ الگویی مطابق با URL درخواستی پیدا نکند یک صفحه‌ی خطا برمی‌گرداند.

دومین نشان‌وند در path() تابعی را تعیین می‌کند که باید در view.py فراخوانی شود. زمانی که URL درخواستی با الگویی که تعریف کردیم منطبق شود جانگو تابع index() را از فایل view.py صدا می‌کند (این تابع را در بخش بعدی می‌نویسیم.) سومین نشان‌وند نام index را به این الگوی URL نسبت می‌دهد تا بتوانیم در بخش‌های دیگر کد به آن ارجاع دهیم. هرگاه بخواهیم پیوندی به صفحه‌ی خانه ارائه کنیم به جای نوشتن یک URL از این نام استفاده می‌کنیم.

نوشتن یک نما

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

فایل views.py در learning_logs هنگام اجرای فرمان python manage.py startapp به طور خودکار ایجاد می‌شود. این چیزی است که هم‌اکنون در views.py می‌بینیم:

1
2
3
from django.shortcuts import render

# Create your views here.

در حال حاضر این فایل فقط تابع render() را وارد می‌کند که پاسخ را بر اساس داده‌هایی که نماها ارائه کرده‌اند ایجاد می‌کند. فایل مربوط به نماها را باز کنید و کد زیر را برای صفحه‌ی خانه اضافه کنید:

1
2
3
4
5
from django.shortcuts import render

def index(request):
    """The home page for Learning Log."""
    return render(request, 'learning_logs/index.html')

زمانی که درخواست یک URL با الگویی که ما تعریف کرده‌ایم منطبق می‌شود جانگو در فایل views.py به دنبال تابعی به نام index() می‌گردد. جانگو سپس شیء request را به تابع نما می‌دهد. در این مورد به پردازش هیچ داده‌ای احتیاج نداریم پس در این تابع تنها فراخوانی تابع render() قرار دارد. تابع render() اینجا دو نشان‌وند می‌گیرد—شیء request اصلی و یک قالب که برای ساختن صفحه مورد استفاده قرار می‌گیرد. بیایید این قالب را بنویسیم.

نوشتن یک قالب

قالب مشخّص می‌کند که صفحه باید چه شکلی باشد و هر بار که صفحه درخواست شود جانگو داده‌های مربوطه را جاگذاری می‌کند. یک قالب به شما امکان می‌دهد که به هر داده‌ای که نما ارائه می‌کند دسترسی داشته باشید. چون نمای صفحه‌ی خانه هیچ داده‌ای در اختیار نمی‌گذارد این قالب به نسبت ساده است.

داخل پوشه‌ی learning_logs پوشه‌ای جدید به نام templates بسازید. داخل آن پوشه‌ی دیگری به نام learning_logs بسازید. این ممکن است اضافه‌کاری به نظر بیاید (داخل پوشه‌ای به نام learning_logs پوشه‌ی templates قرار دارد و دوباره در آن پوشه‌ای به نام learning_logs) امّا این کار ساختاری ایجاد می‌کند که جانگو آن را حتّی در بستر پروژه‌های بزرگ یا چندین برنامه‌ی مجزّا، بدون هیچ ابهامی تفسیر می‌کند. داخل پوشه‌ی learning_logs داخلی فایلی به نام index.html بسازید. مسیر این فایل learning_logs/templates/learning_logs/index.html خواهد بود. این کد را داخل آن فایل بنویسید:

1
2
3
<p>Learning Log</p>
<p>Learning Log helps you keep track of your learning, for any topic you're
learning about.</p>

این فایلی بسیار ساده است. اگر با HTML آشنا نیستید، بدانید که تگ‌های <p></p> پاراگراف‌ها را مشخّص می‌کنند. تگ <p> پاراگراف را باز و </p> آن را می‌بندد. دو پاراگراف داریم: اوّلی مثل یک عنوان است و دومی توضیح می‌دهد که کاربران در Learning Logs چه می‌توانند بکنند.

حال اگر URL پایه‌ی پروژه، http://localhost:8000/، را باز کنید، باید به جای صفحه‌ی پیش‌فرض جانگو، صفحه‌ای را که هم‌اکنون ساخته‌اید ببینید. جانگو URL درخواستی را دریافت می‌کند و چون بر الگوی ’’ منطبق است؛ جانگو تابع views.index() را فرامی‌خواند که صفحه را به کمک قالبی که در index.html قرار گرفته تولید می‌کند.

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

نکته

ممکن است پیام خطای زیر را ببینید:

ModuleNotFoundError: No module named 'learning_logs.urls'

اگر چنین شد سرور توسعه را با فشردن CTRL+C در پنجره‌ی ترمینالی که فرمان runserver را از آن صادر کردید، متوقّف کنید. سپس دستور python manage.py runserver را مجدّداً وارد کنید. باید بتوانید صفحه‌ی خانه را ببینید. هر زمانی که به مشکلی مثل این برخوردید سرور را متوقّف کنید و دوباره راه بیندازید.

خودآزمایی

۱۸-۵: برنامه‌ریز غذایی: برنامه‌ای را در نظر بگیرید که به مردم در تعیین برنامه‌ی غذایی خود در طول هفته کمک می‌کند. پوشه‌ای جدید به نام meal_planner بسازید و داخل آن یک پروژه‌ی جدید جانگو ایجاد کنید. سپس برنامه‌ی جدیدی به نام meal_plans و یک صفحه‌ی خانه‌ی ساده برای این پروژه بسازید.

۱۸-۶: صفحه‌ی خانه‌ی پیتزافروشی: به پروژه‌ی پیتزافروشی که در تمرین ۱۸-۴ شروع کردید، به صفحه‌ی خانه اضافه کنید.

7 - ساختن صفحه‌های اضافی

حال که راه و روش مشخّصی برای ساختن یک صفحه ایجاد کرده‌ایم می‌توانیم ساختن پروژه‌ی Learning Log را شروع کنیم. دو صفحه برای نمایش داده‌ها می‌سازیم: یکی تمام عنوان‌ها را فهرست می‌کند و دیگری تمام موضوعات مرتبط با یک موضوع خاص را نشان می‌دهد. برای هر صفحه یک الگوی URL تعیین می‌کنیم، تابع نمایی می‌نویسیم و یک قالب می‌سازیم. امّا پیش از این یک قالب پایه ایجاد می‌کنیم که تمام قالب‌های این پروژه می‌توانند از آن ارث ببرند.

ارث‌بری قالب‌ها

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

قالب والد

قالبی به نام base.html در همان پوشه‌ی index.html می‌سازیم. این فایل تمام عناصر مشترک صفحه‌ها را دربرمی‌گیرد؛ هر قالب دیگری از base.html ارث خواهد برد. تنها عنصری که فعلاً می‌خواهیم در هر صفحه تکرار کنیم عنوان در بالای هر کدام است. چون این قالب را در هر صفحه‌ای خواهیم آورد بیایید عنوان را به صورتی پیوندی به صفحه‌ی خانه دربیاوریم:

1
2
3
4
5
<p>
  <a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>

{% block content %}{% endblock content %}

اوّلین بخش این فایل پاراگرافی شامل نام پروژه می‌سا162 زد که به صورت پیوندی به صفحه‌ی خانه هم عمل می‌کند. برای تولید یک پیوند از تگ قالب استفاده می‌کنیم که با آکُلاد و علامت درصد {% %} مشخّص می‌شود. هر تگ قالب اطّلاعاتی را برای نمایش در صفحه تولید می‌کند. تگ قالب ما {% url 'learning_logs:index' %} URLای تولید می‌کند که با الگوی URL تعریف‌شده در learning_logs/urls.py به نام ‘index’ مطابقت داشته باشد. در این مثل learning_logs یک فضای نام و index نام منحصربه‌فرد الگوی URL در آن فضای نام است. فضای نام از مقداری می‌آید که به app_name در فایل learning_logs/urls.py نسبت داده‌ایم.

در یک صفحه‌ی HTML ساده پیوندها داخل تگ لنگر <a> قرار می‌گیرد:

1
<a href="link_url">link text</a>

تولید URL به کمک تگ قالب کار را برای به‌روز نگه داشتن پ163 یوندها بسیار ساده‌تر می‌کند. کافی است تنها الگوی URLای که در urls.py تعریف کرده‌ایم تغییر دهیم و جانگو دفعه‌ی بعد که صفحه درخواست شد، به طور خودکار URL جدید را در آن قرار می‌دهد. هر صفحه‌ای در پروژه از base.html ارث می‌برد پس از الان به بعد هر کدام از صفحه‌ها پیوندی برای برگشتن به صفحه‌ی خانه خواهند داشت.

یک جفت تگ block قرار دادیم. این بلوک، با نام content، یک جانگه‌دار است؛ قالب فرزند تعیین خواهد کرد که چه نوع اطّلاعاتی در اینجا قرار می‌گیرد.

الزامی نیست که قالب فرزند تمام بلوک‌های والد خود را تعریف کند بنابراین می‌توانید در قالب والد برای هر تعداد بلوک که می‌خواهید جا نگه دارید؛ قالب فرزند تنها از آن‌هایی که می‌خواهد استفاده خواهد کرد.

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

قالب فرزند

اکنون باید index.html را بازنویسی کنیم تا از base.html ارث ببرد. کد زیر را به index.html اضافه کنید:

1
2
3
4
5
6
{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Learning Log helps you keep track of your learning, for any topic you're
  learning about.</p>
{% endblock content %}

اگر این را با index.html اوّلیّه مقایسه کنید می‌بینید که عنوان Learning Log را به کدی برای ارث‌بری از قالب والد جایگزین کرده‌ایم. یک قالب فرزند باید یک تگ {% extends %} در اوّلین خط بیاورد تا به جانگو بگوید از کدام قالب والد باید ارث ببرد. فایل base.html بخشی از learning_logs است بنابراین learning_logs را در مسیر قالب والد قرار می‌دهیم. این خط همه‌ی آن‌چه که در قالب base.html وجود دارد بیرون می‌کشد و به index.html امکان می‌دهد که فضای نگه‌داشته‌شده در بلوک content را تعریف کند.

بلوک محتوا را و با داخل کردن یک تگ {% block %} با نام content تعریف می‌کنیم. هر چیزی که از قالب والد به ارث نرسد داخل بلوک content قرار می‌گیرد که اینجا یک پاراگراف است که در مورد پروژه‌ی Learning Log توضیح می‌دهد. پایان محتوا را با یک تگ {% endblock content %} معلوم می‌کنیم. تگ {% endblock %} به نام نیاز ندارد امّا اگر قالبی بزرگ شود و چند بلوک را دربربگیرد این که بدانیم کدام بلوک در حال خاتمه است برای ما سودمند است.

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

نکته
در یک پروژه‌ی بزرگ معمول است که یک قالب والد به نام base.html برای کلّ سایت و برای هر بخش مهم سایت هم قالب‌های والد مجزّایی داشته باشیم. تمام قالب‌های این بخش‌ها از base.html ارث می‌برند و هر صفحه‌ی سایت از یکی از قالب‌های بخش‌ها ارث می‌برد. با این کار شما می‌توانید شکل و ظاهر کل سایت، هر بخشی از آن یا هر صفحه را جداگانه تغییر دهید. این پیکربندی روشی بسیار موثّر برای کار کردن ارائه می‌کند و به شما به‌روزسانی دائمی سایت را در طول زمان ترغیب می‌کند.

صفحه‌ی موضوعات

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

الگوی URL موضوع‌ها

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

ما از واژه‌ی topics استفاده می‌کنیم پس URL http://localhost:8000/topics/ این صفحه را باز خواهد گرداند. تغییرات learning_logs/urls.py به شکل زیر است:

1
2
3
4
5
6
7
8
9
"""Defines URL patterns for learning_logs."""
--snip--

urlpatterns = [
    # Home page.
    path('', views.index, name='index'),
    # Page that shows all topics.
    path('topics/', views.topics, name='topics'),
]

topics/ را به سادگی به نشان‌وند رشته‌ای استفاده‌شده در URL صفحه‌ی خانه افزودیم. هنگامی که جانگو URL درخواستی را بررسی می‌کند هر آدرسی که از URL پایه به همراه topics تشکیل شده باشد با این الگو تطبیق خواهد داشت. گذاشتن اسلش در انتها اختیاری است امّا اگر هر چیزی در ادامه topics اضافه کنیم الگو را به هم می‌ریزد. هر درخواستی که URL آن با این الگو مطابق باشد به تابع topics() در view.py فرستاده می‌شود.

نمای موضوعات

تابع topics() باید تعدادی داده را از پایگاه داده بگیرد و آن را به قالب بفرستد. این چیزی است که باید به views.py اضافه کنیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from django.shortcuts import render
from .models import Topic

def index(request):
    --snip--

def topics(request):
    """Show all topics."""
    topics = Topic.objects.order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

ابتدا مدل مربوط به داده‌های مورد نیاز خود را وارد می‌کنیم. تابع topics() یک پارامتر می‌خواهد: شیء requestای که جانگو از سرور دریافت کرده است. در پایگاه داده را برای یافتن شیءهای Topic می‌گردیم و نتایج را بر اساس مشخّصه‌ی date_added مرتّب می‌کنیم. مجموعه‌ی نتایج را در topics ذخیره می‌کنیم.

بستری برای ارسال اطّلاعات به قالب تعریف می‌کنیم. بستر یک د164 یکشنری است که کلیدهای آن نام‌هایی است که در قالب برای دسترسی به داده‌ها استفاده می‌کنیم و مقدارهای آن داده‌هایی است که قرار است به قالب بفرستیم. در این مورد یک جفت کلید-مقدار وجود دارد که شامل مجموعه‌ای موضوعاتی است که در صفحه نمایش می‌دهیم. هنگام ساختن صفحه‌ای که از داده‌ها استفاده می‌کند، متغیّر context، شیء request و مسیر قالب را به render() می‌دهیم.

قالب موضوعات

قالب صفحه‌ی موضوعات دیکشنری context را دریافت می‌کند بنابراین این قالب قادر است که از داده‌های ارائه‌شده‌ی topics() بهره بگیرد. فایلی به نام topics.html در همان پوشه‌ی index.html بسازید. نمایش موضوعات در قالب به این شکل است:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Topics</p>
  <ul>
    {% for topic in topics %}
       <li>{{ topic }}</li>
    {% empty %}
      <li>No topics have been added yet.</li>
    {% endfor %}
  </ul>
{% endblock content %}

درست مانند قالب index، از تگ {% extends %} برای ارث‌بری از base.html استفاده می‌کنیم و سپس یک ب166 165 لوک content باز می‌کنیم. بدنه‌ی این صفحه شامل یک فهرست نشانه‌دار از موضوعاتی است که وارد شده است. در HTML استاندارد فهرست نشانه‌دار فهرست بدون ترتیب نامیده شده و با تگ‌های <ul></ul> نشان داده می‌شود.

از یک تگ قالب دیگر که معادل حلقه‌ی for است استفاده می‌کنیم که در لیست topics موجود در دیکشنری context حلقه می‌زند. کد به‌کاررفته در قالب‌ها از چند منظر مهم با پایتون متفاوت است. پایتون برای مشخّص کردن خط‌های یک عبارت for به عنوان جزئی از حلقه از تورفتگی استفاده می‌کند. در یک قالب هر حلقه‌ی for صریحاً به یک تگ {% endfor %} برای نشان‌دادن نقطه‌ی پایان حلقه نیاز دارد. پس در یک قالب حلقه‌ها را به این شکل خواهید دید:

{% for item in list %}
do something with each item
{% endfor %}

می‌خواهیم که داخل حلقه هر موضوع را به یک مورد در فهرست نشانه‌دار تبدیل کنیم. برای چاپ کردن یک متغیّر در یک قالب نام متغیّر را داخل دو آکُلاد قرار می‌دهیم. پس کد {{ topic }} در هر اجرای حلقه با مقدار topic جایگزین می‌شود. تگ HTML <li></li> یک مورد فهرست را نشان می‌دهد. هر چیزی که در این تگ‌ها، و در کل داخل یک جفت <ul></ul>، به صورت موردی نشانه‌دار نمایش داده می‌شود.

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

اکنون باید قالب پایه را تغییر دهیم و پیوندی به صفحه‌ی موضوعات به آن اضافه کنیم. کد زیر را به base.html بیافزایید:

1
2
3
4
5
6
<p>
  <a href="{% url 'learning_logs:index' %}">Learning Log</a> -
  <a href="{% url 'learning_logs:topics' %}">Topics</a>
</p>

{% block content %}{% endblock content %}

پس از پیوند صفحه‌ی خانه یک خطّ فاصله اضافه می‌کنیم و سپس به کمک تگ قالب {% url %} پیوندی به صفحه‌ی موضوعات اضافه می‌کنیم. این خط به جانگو می‌گوید که پیوندی مطابق با الگوی URL به نام ’topics’ در learning_logs/urls.py ایجاد کن.

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

8 - صفحه‌های جداگانه‌ی هر موضوع

در ادامه باید صفحه‌ای بسازیم که روی یک موضوع تمرکز داشته باشد و نام و تمام مطالب مرتبط با آن موضوع را نشان دهد. ما دوباره یک الگوی URL تعریف می‌کنیم، یک نما می‌نویسیم و قالبی می‌سازیم. سپس صفحه‌ی موضوعات را طوری تغییر می‌دهیم که هر مورد در فهرست نشانه‌دار پیوندی به صفحه‌ی متناظر آن موضوع باشد.

الگوی URL موضوعات

الگوی URL برای صفحه‌ی موضوع با الگوهای قبلی کمی متفاوت است چون از مشخّصه‌ی id موضوع برای تعیین موضوع درخواستی استفاده می‌کند. برای مثال اگر کاربر بخواهد صفحه‌ی جزئیات موضوع شطرنج را ببیند، که id آن ۱ است، URL آن به صورت http://localhost:8000/topics/1/ خواهد بود.

این یک الگو برای تطبیق دادن این URL است که باید آن را در learning_logs/urls.py قرار دهید:

1
2
3
4
5
6
7
--snip--

urlpatterns = [
  --snip--
  # Detail page for a single topic.
  path('topics/<int:topic_id>/', views.topic, name='topic'),
]

اجازه دهید رشته‌ی 'topics/<int:topic_id>/' را در این الگوی URL بررسی کنیم. اوّلین بخش آن به جانگو می‌گوید به دنبال URLهایی بگرد که پس از URL پایه کلمه‌ی topics را داشته باشد. بخش دوم رشته، / <int:topic_id>/ عددی را که بین دو اسلش قرار می‌گیرد دریافت کرده و مقدار عددی آن را در نشان‌وندی به نام topic_id ذخیره می‌کند.

زمانی که جانگو URLای مطابق با این الگو پیدا می‌کند تابع نمای topic() را فرامی‌خواند و مقدار ذخیره‌شده‌ی topic_id را به صورت یک نشان‌وند به آن می‌دهد. داخل تابع از مقدار topic_id برای دریافت صحیح موضوع استفاده می‌کنیم.

نمای موضوع

تابع topic() باید موضوع و تمام مطالب مرتبط با آن را از پایگاه داده بگیرد، مانند زیر:

1
2
3
4
5
6
7
8
--snip--

def topic(request, topic_id):
    """Show a single topic and all its entries."""
    topic = Topic.objects.get(id=topic_id)
    entries = topic.entry_set.order_by('-date_added')
    context = {'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

این اوّلین تابع نمایی است که به جز شیء request یک پارامتر هم می‌خواهد. این تابع مقداری را که از عبارت <int:topic_id> به دست می‌آید گرفته و در topic_id ذخیره می‌کند. درست مانند کاری که در پوسته‌ی جانگو کردیم، از get() برای دریافت موضوع استفاده می‌کنیم. موضوعات مرتبط با این موضوع را می‌گیریم و بر اساس date_added مرتّب می‌کنیم. علامت منفی جلوی date_added باعث مرتّب‌سازی معکوس می‌شود که موضوعات جدیدتر را ابتدا نشان می‌دهد. موضوع و مطالب را در دیکشنری context ذخیره کرده و آن را به قالب topic.html ارسال می‌کنیم.

نکته
عبارت‌های کد در get() و order_by() پرس و جو نامیده می‌شوند زیرا از پایگاه داده در مورد اطّلاعات خاصّی پرس و جو می167 ‌کنند. زمانی که چنین عبارت‌هایی را در پروژه‌های خود می‌نویسید بهتر است ابتدا آن‌ها را در پوسته‌ی جانگو امتحان کنید. بازخوردی که در پوسته می‌گیرید بسیار سریع‌تر از آن است که یک نما و قالب بنویسید و سپس نتایج را در مرورگر بررسی کنید.

قالب موضوع

قالب باید نام موضوع و مطالب مرتبط را نشان دهد. همچنین اگر هیچ موضوعی در این رابطه نوشته نشده باید به کاربر اطّلاع دهیم.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{% extends 'learning_logs/base.html' %}

{% block content %}
  <p>Topic: {{ topic }}</p>
  <p>Entries:</p>
  <ul>
  {% for entry in entries %}
    <li>
       <p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
       <p>{{ entry.text|linebreaks }}</p>
    </li>
  {% empty %}
    <li>There are no entries for this topic yet.</li>
  {% endfor %}
  </ul>
{% endblock content %}

اینجا هم مانند تمام صفحه‌های این پروژه base.html را گسترش داده‌ایم. سپس موضوعی را نشان می‌دهیم که اکنون در حال نمایش است و در متغیّر قالب {{ topic }} ذخیره می‌شود. متغیّر topic در دسترس است چون در دیکشنری context گنجانده شده است. سپس فهرستی بدون ترتیب برای نمایش هر مطلب ایجاد می‌کنیم و مانند آن‌چه برای موضوعات کردیم، داخل آن حلقه می‌زنیم.

هر مورد نشانه‌دار دو جزء اطّلاعات را در برمی‌گیرد: برچسب زمان و متن کامل هر مطلب. برای برچسب زمانی مقدار مشخّصه‌ی date_added را نشان می‌دهیم. در قالب‌های جانگو خط عمودی (|) بیانگر فیلتر قالب است—تابعی که مقدار یک متغیّر قالب را تغییر می‌دهد. فیلتر date:'M d, Y H:i' برچسب زمان به شکل January 1, 2018 23:00 نشان می‌دهد. خط بعدی مقدار کامل text را به جای تنها ۵۰ حرف اوّل entry نمایش می‌دهد. فیلتر linebreaks اطمینان می‌دهد که در متن‌های طولانی شکست خط‌ها به شکلی که برای مرورگرها قابل درک باشند شامل می‌شوند و کل متن به صورت یک نوشته‌ی بدون وقفه نمایش داده نمی‌شود. اگر هیچ مطلبی نوشته نشده باشد، از تگ قالب {% empty %} برای چاپ پیامی خطاب به کاربر استفاده می‌کنیم.

پیوندهای ایجاد شده از صفحه‌ی موضوعات

پیش از آن‌که صفحه‌ی موضوع را در مرورگری ببینیم باید قالب موضوعات را تغییر دهیم تا هر موضوع به صفحه‌ی متناسب خود پیوند داشته باشد. این تغییری است که باید در topics.html ایجاد کنید:

1
2
3
4
5
6
7
8
--snip--

{% for topic in topics %}
  <li>
    <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
  </li>
{% empty %}
--snip--

از تگ قالب URL و بر اساس الگوی URL با نام ’topic’ در learning_logs برای ساختن پیوند مناسب استفاده می‌کنیم. این الگوی URL یک نشان‌وند topic_id می‌خواهد بنابراین مشخّصه‌ی topic.id را به تگ قالب URL اضافه می‌کنیم. اکنون هر موضوع در فهرست موضوعات پیوندی به صفحه‌ی آن موضوع است، مانند http://localhost:8000/topics/1/.

اگر صفحه‌ی موضوعات را به‌روزآوری کنید و روی موضوعی کلیک کنید باید صفحه‌ای مانند شکل ۱۸-۵ ببینید.

نکته
یک تفاوت ظریف امّا مهم بین topic.id و topic_id وجود دارد. عبارت topic.id یک موضوع را بررسی و مقدار ID متناظر با آن را می‌گیرد. متغیّر topic_id ارجاعی به آن ID در کد است. اگر هنگام کار کردن با IDها به خطا برخوردید مطمئن شوید که اینگونه عبارت‌ها را به درستی استفاده می‌کنید.

خودآزمایی

۱۸-۷: مستندات قالب‌سازی: مستندات مربوط به ساختن قالب‌ها را در https://docs.djangoproject.com/en/2.2/ref/templates مرور کنید. می‌توانید هنگامی که بر روی پروژه‌های خود کار می‌کنید به آن دوباره مراجعه کنید.

۱۸-۸: صفحه‌های پیتزافروشی: صفحه‌ای به پروژه‌ی پیتزافروشی در تمرین ۱۸-۶ اضافه کنید که نام پیتزاهای موجود را نمایش دهد. سپس نام هر پیتزا را به صفحه‌ای که مخلّفات آن را نشان می‌دهد پیوند دهید. مطمئن شوید که برای ساختن موثّر صفحه‌های خود از ارث‌بری قالب استفاده می‌کنید.

9 - خلاصه

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

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

در فصل ۱۹ صفحه‌های کاربرپسندی می‌سازید که به کاربران اجازه‌ی افزودن موضوعات و مطالب و ویرایش مطالب موجود را بدون استفاده از سایت مدیر می‌دهد. همچنین سیستم ثبت نام را اضافه خواهید کرد که به کاربران اجازه می‌دهد یک حساب کاربری برای خود بسازند و دفترچه‌ی آموخته‌های خود را ایجاد کنند. این قلب یک برنامه‌ی کاربری تحت وب است—امکان ساختن چیزی که هر تعداد کاربر بتواند با آن تعامل کند.