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

حال که راه و روش مشخّصی برای ساختن یک صفحه ایجاد کرده‌ایم می‌توانیم ساختن پروژه‌ی 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 را خواهید دید. اگر روی آن کلیک کنید به صفحه‌ی موضوعات هدایت خواهید شد.