فیلترهای سفارشی – Custom Filters


هرچند جنگو مجموعه کاملی از تگ‌­ها و فیلترها را معرفی کرده و در اختیار توسعه‌­گران قرار داده است، اما براساس نیازهای هر پروژه ممکن است تگ و یا فیلتری مورد نیاز باشد که در لیست تگ­‌های معرفی شده جنگو نباشد. در این­جا جنگو امکانی را فراهم آورده که بتوان در راحت‌­ترین شکل ممکن یک فانکشن پایتون را بر اساس نیاز decorate کرد و به عنوان یک custom template filter ثبت کرد. برای این منظور داخل دایرکتوری coreapp، یک دایرکتوری جدید به نام templatetags ایجاد کرده و سپس با ایجاد صرفا یک فایل خالی از محتوا با عنوان __init__.py داخل آن، دایرکتوری templatetags را به­‌عنوان پکیج پایتون مطرح می‌کنیم.

هرچند جنگو، مجموعه‌ای غنی و کامل از تگ‌ها و فیلترهای داخلی را در اختیار توسعه‌دهندگان قرار داده است، اما در پروژه‌های واقعی اغلب با نیازهایی مواجه می‌شویم که پوشش داده نشده‌اند. برای پاسخگویی به این نیازها، جنگو امکانی انعطاف‌پذیر فراهم کرده است. می‌توانیم توابع پایتونی خود را به سادگی با دکوراتورهای – decorator – اختصاصی، به عنوان فیلتر یا تگ سفارشی تمپلیت ثبت نمود و مستقیماً در تمپلیت‌ها از آن‌ها استفاده کرد.

برای پیاده‌سازی این قابلیت، در اپلیکیشن مورد نظر (مثلاً coreapp)، یک دایرکتوری با نام templatetags ایجاد نموده و سپس، برای تبدیل این دایرکتوری به یک پکیج پایتون، یک فایل خالی با نام __init__.py در آن قرار می‎‌دهیم.

پس از این مرحله، جنگو قادر خواهد بود فایل‌های داخل templatetags را شناسایی کرده و توابع ثبت‌شده در آن‌ها را به عنوان تگ یا فیلتر در تمپلیت‌ها در دسترس قرار دهد. این رویکرد، توسعه‌دهندگان را قادر می‌سازد تا منطق‌های تکراری یا پیچیده را از توابع view خارج کرده و مستقیماً در لایه تمپلیت مدیریت کنند — بدون نقض اصول MVC و با حفظ خوانایی و قابلیت نگهداری کد.

├───coreapp
    │   admin.py
    │   apps.py
    │   models.py
    │   tests.py
    │   utls.py
    │   views.py
    │   __init__.py
    │
    └───templatetags
            __init__.py          # Must Exist (Mandatory).
            customtags.py        # Main File for Custom Filter Functions' Definition 

در این مرحله، فایل دیگری با ­نام دلخواه customtags.py داخل دایرکتوری templatetags/ ایجاد کرده تا تگ‌­ها و فیلترهای سفارشی را داخل آن تعریف و استفاده نمود. ذکر این نکته حائز اهمیت است که برای استفاده از تگ‌­ها و یا فیلترهای سفارشی در تمپلیت حتما می­‌بایست از تگ {% load %} و به صورت (% load customtags %} در ابتدای تمپلیتی که قرار است از تگ­ها و یا فیلترهای سفارشی استفاده کند، بهره گرفت.

coreapp/templatetags/customtags.py

from django import template

register = template.Library()

حال می‌توانیم یک فیلتر تمپلیت سفارشی (Custom Template Filter) ایجاد کنیم که عملکردی مشابه متد str.split() در پایتون داشته باشد. این فیلتر به ما امکان می‌دهد رشته‌های ذخیره‌شده در مدل (مثلاً تگ‌ها، لیست کلمات کلیدی، یا مقادیر CSV) را مستقیماً در تمپلیت‌ها، بر اساس یک جداکننده (delimiter) به لیستی از آیتم‌ها تقسیم کنیم — بدون نیاز به پیش‌پردازش در ویوها.

coreapp/templatetags/customtags.py
from django import template

register = template.Library()

@register.filter
def split(value, delimiter = ","):
    return value.split(delimeter)

برای استفاده از فیلتر سفارشی split که در فایل customtags.py تعریف نمودیم، اولین و ضروری‌ترین گام، وارد کردن کتابخانه مربوطه در ابتدای تمپلیت مورد نظر است. این کار با استفاده از تگ {% load customtags %} انجام می‌شود این دستور باید فقط یک‌بار در هر تمپلیت قرار گیرد — حتی اگر از چندین فیلتر یا تگ موجود در customtags.py استفاده گردد. همچنین، این دستور باید قبل از استفاده از فیلترها در تمپلیت آمده باشد، در غیر این صورت با خطای Invalid filter: 'split' مواجه خواهیم شد.

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

{% extends "base.html" %}
{% load customtags %}  ← This is a vital line!

{% block content %}
  <h2>Post Tags</h2>
  <div>
    {% for tag in post.tags|split:"-" %}
      <span>{{ tag|capfirst }}</span>
    {% endfor %}
  </div>
{% endblock content %}

 

━◦○◦ نکته‌های تکمیلی ◦○◦━

⮜ اگر از چندین فایل templatetags استفاده می‌کنیم (مثلاً customtags.py و coretags.py)، می‌توان همه را در یک خط {% load customtags coretags %} وارد تمپلیت نمود.

⮜ برای جلوگیری از تکرار، می‌توان {% load customtags %} را در base.html قرار داد — در این صورت تمام تمپلیت‌هایی که از آن extend می‌کنند، به‌صورت خودکار فیلترها را در دسترس خواهند داشت.