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

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

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