ایجاد داده – Create


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

گام اول: ایجاد View برای نمایش فرم

اولین قدم، تعریف یک View در فایل views.py خواهد بود که فرم مربوطه را به کاربر نمایش دهد.

💡 نکته: در این مرحله فقط فرم را نمایش می‌دهیم. ذخیره‌سازی داده در مرحله بعدی (با مدیریت درخواست POST) انجام می‌شود.

coreapp/views.py

from . import forms

 def ProjectCreate(request):

    projectForm = forms.ProjectForm()
    context = {'form': projectForm }
    return render(request, 'forms.html', context)

 

گام دوم: تعریف مسیر (URL) مربوط به View

حال باید یک الگوی مسیر (URL) برای دسترسی به View ایجاد شده، در فایل urls.py تعریف گردد.

coreapp/urls.py

urlpatterns = [
    ...,
    path('project-add/', views.ProjectCreate, name='ProjectCreate'),
]

 

 گام سوم: ایجاد تمپلیت عمومی برای فرم‌ها

در مرحله پایانی به سراغ ایجاد تمپلیت عمومی forms.html در دایرکتوری ریشه پروژه خواهیم رفت. یکی از مزیت‌های جنگو این است که می‌توان یک تمپلیت عمومی برای تمام فرم‌های ایجاد (Create) و ویرایش (Update) طراحی نمود. که تمامی مدل‌ها را پوشش دهد. این کار از تکرار کد جلوگیری کرده و نیاز به ایجاد تمپلیت‌های فرم متعدد برای مدل‌های مختلف را — مگر در مواردی خاص — از بین می‌برد.


tutorial/templates/forms.html

{% extends 'base.html' %}

{% block content %}
<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Save</button>
</form>
{% endblock %}


جنگو به‌صورت پیش‌فرض از CSRF (Cross-Site Request Forgery) محافظت می‌کند. تگ {% csrf_token %} یک توکن امنیتی در فرم قرار می‌دهد که بدون آن، جنگو هر درخواست POST را رد کرده و خطای 403 Forbidden نمایش می‌دهد. همواره در هر فرمی که از method="POST" استفاده می‌کند، می‌بایست تگ {% csrf_token %} را  قرار دهیم.

هنگام استفاده از تگ {{ form.as_p }}، جنگو به‌صورت خودکار تمام فیلدهای فرم را به‌صورت یک سری تگ <p> (پاراگراف) رندر می‌کند. هر فیلد در یک تگ <p> جداگانه قرار می‌گیرد که شامل برچسب (label) و ورودی (input) فیلد مربوطه خواهد بود و زمانی کاربردی خواهد بود که بخواهیم سریعا یک فرم قابل استفاده داشته باشیم (مثلا در مرحله توسعه یا پروتوتایپ) و نیازی به کنترل دقیق روی ظاهر فرم نداشته باشیم.

پس از اتمام مراحل، می‌توان نمایشی از فیلد­ها را برای ایجاد پروژه جدید با رجوع به آدرس project-add/ در مرورگر، مشاهده کرد.

در پروژه‌های نهایی (production) که ظاهر کاربری مهم است و یا زمانی که نیاز به نمایش پیغام‌های خطا (Errors)، متن‌های راهنما (Help Text) یا استایل‌دهی پیشرفته داشته باشیم، بهتر است فرم عمومی forms.html را به‌صورت دستی و با بهره‌گیری از حلقه رندر کنیم.

tutorial/templates/forms.html

{% extends 'base.html' %}
{% block content %}
  <form method="POST">
    {% csrf_token %}    
    {% for field in form %}
      <div class="mb-3">
        {{ field.label_tag }}
        {{ field }}
        {% if field.help_text %}
            <small>{{ field.help_text }}</small>
        {% endif %}
        {% if field.errors %}
            <div>{{ field.errors }}</div>
        {% endif %}
      </div>
    {% endfor %}
    <button type="submit">Save</button>  
  </form>
{% endblock %}

 

تا به اینجا، تنها به نمایش تمپلیت فرم برای ایجاد پروژه در مدل Project توسط مدل–فرم ProjectForm پرداختیم. حال در ادامه می‌­بایست به پردازش داده‌های ارسالی از طریق فرم و ذخیره آن‌ها در پایگاه داده بپردازیم که یکی از هسته‌های اصلی کار با فرم‌ها در Django است

 

گام چهارم: پردازش و ذخیره‌سازی داده‌ها

 

    if request.method == 'POST':
      data = forms.ProjectForm(request.POST)
      if data.is_valid():
          data.save()
          return redirect('Projects')

 

— بررسی نوع درخواست

وقتی کاربر روی Submit فرم کلیک می‌کند، مرورگر یک درخواست HTTP از نوع POST به سرور ارسال می‌کند.. در view می‌بایست در ابتدای کار نوع درخواست ارسالی را توسط if request.method == 'POST' بررسی نمود. این بررسی، اولین سطح از منطق کنترل جریان پردازش و دخیره‌سازی داده‌ها در View می‌باشد.

  • request.method نشان می‌دهد که این درخواست از چه نوعی است (GE
  • فقط زمانی داده‌ها پردازش خواهند شد که درخواست از نوع POST باشد (یعنی کاربر، داده ارسال نموده باشد).
  • T، POST، PUT و غیره).اگر درخواست از نوع GET باشد (مثلا وقتی کاربر صفحه را برای اولین بار باز می‌کند)، این بلوک اجرا نمی‌شود و معمولا یک فرم خالی نمایش داده می‌شود.

 

 ایجاد نمونه فرم با داده‌های ارسالی

در این مرحله با دستور formData = ProjectForm(request.POST) فقط داده‌ها را دریافت و به فرم نسبت می‌دهیم — هنوز هیچ اعتبارسنجی یا ذخیره‌سازی انجام نشده است.
  • ProjectForm یک کلاس فرم است که از forms.ModelForm ارث‌بری کرده و مربوط به مدل Project است.
  • request.POST یک دیکشنری‌ مانند (QueryDict) بوده که تمام داده‌های ارسالی از طریق فرم (با متد POST) را در خود دارد.
  • با ارسال request.POST به سازنده فرم ProjectForm(...), جنگو یک نمونه پر شده از فرم ایجاد می‌کند که داده‌های واردشده توسط کاربر را در خود نگه می‌دارد.
 

 اعتبارسنجی داده‌ها

اعتبارسنجی داده‌ها با متد is_valid() یکی از قدرتمندترین ویژگی‌های جنگو است چرا که از خطاهای انسانی (مثل وارد کردن ایمیل نامعتبر) و حملات امنیتی (مثل تزریق داده — Data Injection ) جلوگیری می‌کند.

  • تمام فیلدهای فرم را بر اساس قوانین تعریف‌شده در مدل یا فرم (مثل max_length، required، validators و غیره) بررسی می‌کند.
    • اگر همه داده‌ها معتبر باشند:
      • مقدار True برگردانده می‌شود.
      • داده‌های تمیزشده (cleaned data) در ویژگی formData.cleaned_data قرار می‌گیرند.
    • اگر حتی یک فیلد نامعتبر باشد:
      • مقدار False برگردانده می‌شود.
      • خطاهای مربوطه در formData.errors ذخیره می‌شوند و می‌توان آن‌ها را در تمپلیت نمایش داد.
 

 ذخیره داده در پایگاه داده

اگر فرم معتبر باشد، از آنجا که ProjectForm یک ModelForm است، متد save() به‌صورت خودکار:

  • یک رکورد — Object — جدید از مدل Project ایجاد می‌کند.
  • مقادیر فیلدها را از cleaned_data به آن Object اختصاص می‌دهد.
  • Object را با فراخوانی save()، در پایگاه داده ذخیره می‌کند (یک رکورد جدید در جدول project ایجاد می‌شود).
💡 اگر فرم از forms.Form (نه ModelForm) ارث‌بری کرده بود، متد save() دیگر وجود نخواهد داشت و باید به‌صورت دستی داده‌ها را در مدل ذخیره نمود.
 

 هدایت مجدد کاربر

پس از ذخیره موفقیت‌آمیز داده، به‌جای بازگرداندن یک صفحه جدید یا نمایش پیام، می‌توان کاربر را به یک URL دیگر هدایت کرد. این کار با بهره‌گیری از متد redirect , بر اساس الگوی طراحی معروف PRG (Post-Redirect-Get) انجام می‌شود.

چرا این کار مهم است؟

  • جلوگیری از ارسال مجدد تصادفی فرم (اگر کاربر F5 بزند، دوباره داده ذخیره نمی‌شود).
  • رفتار استاندارد و امن در وب.
  • بهبود تجربه کاربری (مثلا هدایت به لیست پروژه‌ها پس از ایجاد یک پروژه جدید).
⚠️ در متد redirect از مقداری که برای متغیر name — در اینجا name="Projects" — برای الگوی URL در لیست urlpatterens=[] تعریف شده، برای فراخوانی URL استفاده می‌گردد.

⚠️ برای استفاده از redirect، می‌بایست متد آن را از کتابخانه django.shortcuts وارد نمود

 
درنهایت، view مربوط به ایجاد داده به‌صورت زیر خواهد بود.
coreapp/views.py
from django.shortcuts import render, redirect

def ProjectCreate(request):

    projectForm = forms.ProjectForm()

    if request.method == 'POST':
      data = forms.ProjectForm(request.POST)
      if data.is_valid():
          data.save()
          return redirect('Projects')

    context = {'form': projectForm }
    return render(request, 'forms.html', context)

 

⚠️ برای نمایش خطاها در صورت نامعتبر بودن فرم، می‌بایست حتما فرم را دوباره به تمپلیت برگردانیم.
    if request.method == 'POST':
      data = forms.ProjectForm(request.POST)
      if data.is_valid():
          ...
      else:
        projectForm = forms.ProjectForm()

    context = {'form': projectForm }
    return render(request, 'forms.html', context)
 
 

⚠️ هرگاه فرم شامل آپلود فایل باشد، باید request.FILES را هم به فرم اضافه نماییم 

data = ProjectForm(request.POST, request.FILES)
 
در این‌صورت تمپلیت فرم هم می‌بایست گزینه enctype="multipart/form-data" را در اختیار داشته باشد.
<form class="" action="" method="POST" enctype="multipart/form-data"> 
    ...
</form>