حلقه‌زدن روی فیلدهای فرم در جنگو و مدیریت فیلدهای مخفی و قابل‌مشاهده

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

BoundFieldفیلد مخفیحلقه فرم

~8 دقیقه مطالعه • بروزرسانی ۲۳ اسفند ۱۴۰۴

مقدمه

در بسیاری از پروژه‌های جنگو، نیاز داریم فیلدهای فرم را به صورت پویا و تکرارشونده نمایش دهیم. این کار باعث کاهش کدهای تکراری و افزایش انعطاف‌پذیری قالب‌ها می‌شود. جنگو با ارائه BoundField و متدهای کمکی، امکان کنترل کامل روی رندر فیلدها را فراهم می‌کند.


حلقه‌زدن روی فیلدهای فرم

اگر برای هر فیلد از HTML مشابهی استفاده می‌کنید، می‌توانید با یک حلقه {% for %} کدهای تکراری را حذف کنید:


{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
        {% if field.help_text %}
          <p class="help" id="{{ field.auto_id }}_helptext">
            {{ field.help_text|safe }}
          </p>
        {% endif %}
    </div>
{% endfor %}

ویژگی‌های مهم BoundField

هر field در حلقه یک BoundField است و ویژگی‌های مفیدی دارد:

  • field.errors: نمایش خطاهای اعتبارسنجی به صورت <ul class="errorlist">.
  • field.field: دسترسی به شیء اصلی Field و ویژگی‌هایی مانند max_length.
  • field.help_text: نمایش متن راهنما.
  • field.html_name: نام HTML فیلد.
  • field.id_for_label: شناسه HTML برای استفاده در <label>.
  • field.is_hidden: تشخیص اینکه فیلد مخفی است یا نه.
  • field.label: متن برچسب فیلد.
  • field.label_tag: برچسب HTML کامل.
  • field.legend_tag: مشابه label_tag اما با <legend>.
  • field.use_fieldset: مشخص می‌کند آیا فیلد باید داخل <fieldset> قرار گیرد.
  • field.value: مقدار فعلی فیلد.

استفاده از fieldset برای ویجت‌های چندبخشی

اگر ویجت فیلد شامل چند ورودی باشد، می‌توان آن را داخل fieldset قرار داد:


{% if field.use_fieldset %}
  <fieldset>
  {% if field.label %}{{ field.legend_tag }}{% endif %}
{% else %}
  {% if field.label %}{{ field.label_tag }}{% endif %}
{% endif %}
{{ field }}
{% if field.use_fieldset %}</fieldset>{% endif %}

حلقه‌زدن روی فیلدهای مخفی و قابل‌مشاهده

برای مدیریت جداگانه فیلدهای مخفی و قابل‌مشاهده، جنگو دو متد ارائه می‌دهد:

  • hidden_fields()
  • visible_fields()

نمونه:


{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}

{% for field in form.visible_fields %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

رندر دستی فیلدها

برای کنترل کامل روی ظاهر فیلدها، می‌توان آن‌ها را به صورت دستی رندر کرد:


{{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.subject.errors }}
    <label for="{{ form.subject.id_for_label }}">Email subject:</label>
    {{ form.subject }}
</div>

نمایش خطاهای فرم

خطاهای هر فیلد با {{ field.errors }} نمایش داده می‌شوند:


<ul class="errorlist">
    <li>Sender is required.</li>
</ul>

برای سفارشی‌سازی بیشتر:


{% if form.subject.errors %}
    <ol>
    {% for error in form.subject.errors %}
        <li><strong>{{ error|escape }}</strong></li>
    {% endfor %}
    </ol>
{% endif %}

جمع‌بندی

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

مقدمه

جنگو از سیستم قدرتمندی برای مدیریت template engines استفاده می‌کند. این سیستم امکان استفاده از چندین موتور قالب، بارگذاری پویا، رندر قالب‌ها و مدیریت خطاهای مرتبط با قالب‌ها را فراهم می‌کند. تنظیمات مربوط به موتورهای قالب در بخش TEMPLATES قرار دارد.


پیکربندی موتورهای قالب

موتورهای قالب از طریق تنظیم TEMPLATES پیکربندی می‌شوند. این تنظیم یک لیست از دیکشنری‌هاست که هر کدام یک موتور قالب را تعریف می‌کنند:


TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "APP_DIRS": True,
        "OPTIONS": {
            # ...
        },
    },
]

مقدار BACKEND مسیر پایتونی کلاسی است که موتور قالب را پیاده‌سازی می‌کند. موتورهای داخلی شامل:

  • django.template.backends.django.DjangoTemplates
  • django.template.backends.jinja2.Jinja2

دو تنظیم مهم دیگر:

  • DIRS: مسیرهایی که موتور قالب باید در آن‌ها به دنبال فایل‌های قالب بگردد.
  • APP_DIRS: مشخص می‌کند آیا قالب‌ها از داخل اپلیکیشن‌ها نیز بارگذاری شوند یا نه.

بارگذاری قالب‌ها

ماژول django.template.loader دو تابع اصلی برای بارگذاری قالب‌ها ارائه می‌دهد:


تابع get_template

این تابع قالبی با نام مشخص را بارگذاری می‌کند:


from django.template.loader import get_template

template = get_template("template.html")

اگر قالب پیدا نشود، خطای TemplateDoesNotExist و اگر قالب دارای خطای نحوی باشد، خطای TemplateSyntaxError رخ می‌دهد.


بارگذاری partial

در جنگو ۶.۰ امکان بارگذاری بخش‌های خاص یک قالب با استفاده از # اضافه شده است:


partial = get_template("template.html#partial_name")

تابع select_template

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


template = select_template(["story_253_detail.html", "story_detail.html"])

مدیریت خطاهای قالب

دو استثنای مهم در هنگام بارگذاری قالب‌ها:

  • TemplateDoesNotExist: زمانی که قالب پیدا نشود.
  • TemplateSyntaxError: زمانی که قالب دارای خطای نحوی باشد.

رندر قالب‌ها

تمام قالب‌های بارگذاری‌شده دارای متد render() هستند:


template.render({"foo": "bar"})

اگر request ارسال شود، موتور قالب باید آن را در دسترس قرار دهد.


مثال الگوریتم جستجوی قالب

فرض کنید تنظیمات زیر را داریم:


TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            "/home/html/example.com",
            "/home/html/default",
        ],
    },
    {
        "BACKEND": "django.template.backends.jinja2.Jinja2",
        "DIRS": [
            "/home/html/jinja2",
        ],
    },
]

اگر فراخوانی کنیم:


get_template("story_detail.html")

جنگو به ترتیب زیر جستجو می‌کند:

  • /home/html/example.com/story_detail.html
  • /home/html/default/story_detail.html
  • /home/html/jinja2/story_detail.html

استفاده از render_to_string

برای کاهش تکرار در بارگذاری و رندر قالب‌ها، تابع render_to_string ارائه شده است:


from django.template.loader import render_to_string

rendered = render_to_string("my_template.html", {"foo": "bar"})

جمع‌بندی

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

مقدمه

جنگو از یک سیستم قدرتمند برای مدیریت template engines استفاده می‌کند. این سیستم امکان استفاده از چندین موتور قالب، بارگذاری پویا، رندر قالب‌ها و افزودن قابلیت‌های سفارشی را فراهم می‌کند. موتورهای قالب از طریق django.template.engines قابل دسترسی هستند.


دسترسی به موتورهای قالب

برای دسترسی به موتورهای قالب پیکربندی‌شده:


from django.template import engines

django_engine = engines["django"]
template = django_engine.from_string("Hello {{ name }}!")

کلید 'django' همان مقدار NAME موتور قالب است.


موتورهای داخلی قالب

DjangoTemplates

برای استفاده از موتور قالب جنگو، مقدار BACKEND باید برابر باشد با:


"django.template.backends.django.DjangoTemplates"

اگر APP_DIRS=True باشد، موتور قالب به دنبال پوشه templates در اپلیکیشن‌های نصب‌شده می‌گردد.


گزینه‌های قابل تنظیم در DjangoTemplates

  • autoescape: فعال یا غیرفعال کردن escape خودکار HTML (پیش‌فرض: True).
  • context_processors: لیستی از توابعی که داده‌های اضافی را به context اضافه می‌کنند.
  • debug: فعال‌سازی حالت اشکال‌زدایی قالب.
  • loaders: کلاس‌های بارگذاری‌کننده قالب.
  • string_if_invalid: مقدار خروجی برای متغیرهای نامعتبر.
  • file_charset: کاراکترست فایل‌های قالب (پیش‌فرض: utf‑8).
  • libraries: ثبت کتابخانه‌های تگ سفارشی.
  • builtins: افزودن کتابخانه‌های تگ به صورت پیش‌فرض.

موتور قالب Jinja2

برای استفاده از Jinja2 باید آن را نصب کنید:


pip install Jinja2

سپس مقدار BACKEND را تنظیم کنید:


"django.template.backends.jinja2.Jinja2"

گزینه‌های مهم Jinja2

مهم‌ترین گزینه environment است که مسیر تابع سازنده محیط Jinja2 را مشخص می‌کند. جنگو به صورت خودکار مقادیر زیر را تنظیم می‌کند:

  • autoescape=True
  • loader بر اساس DIRS و APP_DIRS
  • auto_reload=settings.DEBUG
  • undefined بر اساس حالت DEBUG

استفاده از context_processors در Jinja2

استفاده از context processor در Jinja2 توصیه نمی‌شود، زیرا Jinja2 امکان فراخوانی توابع با آرگومان را دارد. بهتر است توابع مورد نیاز را در env.globals قرار دهید.


مثال پیکربندی محیط Jinja2


from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment

def environment(**options):
    env = Environment(**options)
    env.globals.update({
        "static": static,
        "url": reverse,
    })
    return env

نمونه استفاده در قالب Jinja2:


Admin

تفاوت تگ‌ها و فیلترها در Jinja2 و DTL

هر دو سیستم از تگ‌ها و فیلترها پشتیبانی می‌کنند، اما Jinja2 به دلیل امکان ارسال آرگومان به توابع، بسیاری از قابلیت‌ها را ساده‌تر پیاده‌سازی می‌کند. همچنین Jinja2 دارای سیستم تست‌ها است که در DTL وجود ندارد.


جمع‌بندی

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

نوشته و پژوهش شده توسط دکتر شاهین صیامی