افزودن مطالب جدید

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

فرم مدل موضوع

ما باید فرمی در ارتباط با مدل Entry بسازیم امّا این بار نسبت به TopicForm کمی بیشتر آن را شخصی می‌کنیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from django import forms

from .models import Topic, Entry

class TopicForm(forms.ModelForm):
    --snip--

class EntryForm(forms.ModelForm):
    class Meta:
        model = Entry
        fields = ['text']
        labels = {'text': 'Entry:'}
        widgets = {'text': forms.Textarea(attrs={'cols': 80})}

عبارت import را به‌روز می‌کنیم تا Entry را هم مانند Topic وارد کنیم. کلاس جدیدی به نام EntryForm می‌سازیم که از forms.ModelForm ارث می‌برد. کلاس EntryForm کلاسی داخلی به نام Meta دارد که مدلی را که بر آن بنا شده و فیلدهایی را که باید در فرم بیاورد فهرست می‌کند. دوباره به فیلد text یک برچسب خالی می‌دهیم (۱).

در ۲ مشخّصه‌ی widgets را اضافه می‌کنیم. ویجت یا ابزاره نوعی عنصر فرم HTML اس171 ت، مانند یک ورودی متن یک‌خطّی، ورودی متنی چندخطّی یا یک فهرست پایین‌افتادنی. با اضافه کردن مشخّصه‌ی widgets می‌توانید ویجت‌های انتخابی پیش‌فرض جانگو را تغییر دهید. وقتی به جانگو می‌گوییم که از یک forms.Textarea استفاده کند ویجت ورودی فیلد text را شخصی می‌کنیم تا عرض آن به جای ۴۰ ستونِ پیش‌فرض، به اندازه‌ی ۸۰ ستون باشد. این کار فضایی مناسب برای نوشتن یک مطلب معنادار ایجاد می‌کند.

آدرس new_entry

موضوعات جدید باید در رابطه با موضوع خاصّی باشند پس نیاز داریم که نشان‌وند topic_id را در URL مربوط به اضافه کردن مطلب جدید بیاوریم. این URLایست که آن را به learning_logs/urls.py اضافه می‌کنیم:

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

urlpatterns = [
    --snip--
    # Page for adding a new entry
    path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
]

هر آدرسی به شکل http://localhost:8000/new_entry/id/ با این الگوی URL مطابق خواهد بود که در آن id شماره‌ای برابر با ID موضوع خواهد بود. کد <int:topic_id> مقداری عددی را استخراج و آن را به متغیّر topic_id نسبت می‌دهد. زمانی که آدرسی با الگوی فوق درخواست شد جانگو آن را به همراه شماره‌ی موضوع به تابع نمای new_entry() می‌فرستد.

تابع نمای new_entry()

تابع نمای new_entry بسیار شبیه به تابع اضافه کردن موضوع جدید است. این کد را به فایل views.py اضافه کنید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from django.shortcuts import render, redirect

from .models import Topic
from .forms import TopicForm, EntryForm

--snip--

def new_entry(request, topic_id):
    """Add a new entry for a particular topic."""
    topic = Topic.objects.get(id=topic_id)

    if request.method != 'POST':
        # No data submitted; create a blank form.
        form = EntryForm()
    else:
        # POST data submitted; process data.
        form = EntryForm(data=request.POST)
        if form.is_valid():
            new_entry = form.save(commit=False)
            new_entry.topic = topic
            new_entry.save()
            return redirect('learning_logs:topic', topic_id=topic_id)

    # Display a blank or invalid form.
    context = {'topic': topic, 'form': form}
    return render(request, 'learning_logs/new_entry.html', context)

عبارت import را برای اضافه کردن EntryForm تغییر می‌دهیم. در تعریف new_entry() یک پارامتر topic_id وجود دارد که مقدار دریافت شده از URL در آن ذخیره می‌شود. موضوع مربوطه را برای ساختن صفحه و پردازش داده‌های فرم نیاز دارید پس از در ۱ از topic_id استفاده می‌کنیم تا شیء موضوع درست را دریافت کنیم.

در ۲ بررسی می‌کنیم که آیا متد درخواست GET است یا POST. اگر GET باشد کد داخل if اجرا می‌شود و نمونه‌ای خالی از EntryForm می‌سازد (۳).

اگر نوع درخواست POST باشد با ساختن یک نمونه از EntryForm و انتقال داده‌های POST داخل شیء request به آن، داده‌ها را پردازش می‌کنیم (۴). سپس اعتبار فرم را بررسی می‌کنیم. اگر معتبر بود باید پیش از ذخیره کردن شیء در پایگاه داده مشخّصه‌ی topic آن را تعیین کنیم. زمانی که save() را صدا می‌کنیم نشان‌وند commit=False را به آن می‌دهیم (۵) تا جانگو بداند باید برای موضوع جدید شیء جدیدی ایجاد کند و آن را به new_entry نسبت دهد امّا فعلاً آن را در پایگاه داده ذخیره نکند. مقدار مشخّصه‌ی new_entry را برابر با موضوعی قرار می‌دهیم که در ابتدای تابع از پایگاه داده خواندیم (۶). سپس save() را بدون هیچ نشان‌وندی فرامی‌خوانیم تا موضوع را به همراه موضوع مرتبط با آن در بانک اطّلاعاتی ذخیره کنیم.

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

در پایان تابع یک دیکشنری context ایجاد می‌کنیم و صفحه را به کمک قالب new_entry.html ایجاد می‌کنیم. این کد زمانی اجرا خواهد شد که فرم خالی درخواست شده باشد یا فرم ثبت‌شده معتبر نباشد.

قالب new_entry

چنانکه در کد زیر می‌بینید قالب new_entry شبیه به قالب new_topic است:

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

{% block content %}
  <p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
  <p>Add a new entry:</p>
  <form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
    {% csrf_token %}
    {{ form.as_p }}
    <button name='submit'>Add entry</button>
  </form>

{% endblock content %}

موضوع را در بالای صفحه نمایش می‌دهیم (۱) تا کاربر بتواند ببیند که درباره‌ی چه موضوعی مطلب می‌نویسد. موضوع همچنین به عنوان پیوندی برای بازگشت به صفحه‌ی اصلی آن موضوع هم به کار می‌رود.

نشان‌وند action فرم مقدار topic_id داخل URL را هم دربرمی‌گیرد تا تابع نما بتواند بین مطلب جدید و موضوع مرتبط با آن ارتباط برقرار کند (۱). به جز این قالب کاملاً شبیه به new_topic.html است.

ایجاد پیوند به صفحه‌ی new_entry

در گام بعدی باید از هر صفحه‌ی موضوع در قالب مربوط به موضوعات پیوندی به صفحه‌ی new_entry ایجاد کنیم:

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

{% block content %}
  <p>Topic: {{ topic }}</p>
  <p>Entries:</p>
  <p>
    <a href="{% url 'learning_logs:new_entry' topic.id %}">Add new entry</a>
  </p>
  <ul>
  --snip--
  </ul>

{% endblock content %}

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

![][image48]

شکل ۱۹-۲: صفحه‌ی new_entry