اگر تصور کردی Jinja2 فقط یک سری تگِ {{ }} ساده است که قرار است چند تا متغیر را وسط HTML پرت کند، دقیقاً همان‌جایی هستی که پروژه ‌ات پتانسیل تبدیل شدن به یک فاجعه را دارد. در Flask، موتور Jinja2 در واقع بخشی از لایه بیرونی (Infrastructure) یا همان Delivery Mechanism شماست. وظیفه ‌اش چیست؟ تبدیل داده ‌های خامی که از Use Caseها می‌ آیند به چیزی که کاربر بتواند ببیند و با آن تعامل کند.

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

ارث‌بری (Inheritance): استراتژیِ «یک‌بار بنویس، همه‌جا استفاده کن»

بزرگترین نشانه یک پروژه آماتور، کپی-پیست کردنِ Navbar و Footer در تمام فایل‌های HTML است. در Jinja2، ما از مفهوم Template Inheritance استفاده میکنیم تا نظم را در کل فرانت‌ اند حاکم کنیم.

ما یک فایل پایه (مثلاً layout.html) میسازیم که اسکلت اصلی است و بقیه صفحات فقط بخش ‌های خاصی از آن را پر می‌کنند.

<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
    <title>{% block title %}{% endblock %} | سیستم من</title>
</head>
<body>
    <nav>منوی اصلی</nav>
    
    <div class="content">
        {% block content %}{% endblock %}
    </div>

    <footer>کپی‌رایت ۲۰۲۶</footer>
</body>
</html>

حالا وقتی میخواهی صفحه پروفایل را بسازی، به جای ۳۰۰ خط کد، فقط روی "اصل مطلب" تمرکز میکنی:

{% extends "layout.html" %}

{% block title %}پروفایل کاربری{% endblock %}

{% block content %}
    <h1>سلام {{ user.name }}!</h1>
{% endblock %}

فیلترها (Filters): آرایشگرهای لایه نمایش

فیلترها (Filters): آرایشگرهای لایه نمایش

یک قانون طلایی در Clean Architecture: منطقِ فرمت کردن دیتا نباید در Core پروژه باشد. مثلاً اگر قرار است قیمت‌ ها را سه‌رقم سه‌رقم جدا کنی یا تاریخ میلادی را به شمسی تبدیل کنی، جایش توی Entity یا Use Case نیست! این‌ها جزئیات نمایش هستند.

Jinja2 با Filters این کار را برایت انجام می‌دهد. به جای اینکه در پایتون رشته ‌ها را دست ‌کاری کنی، در قالب این‌طور می‌نویسی:

  • {{ user.balance | separate_thousands }} (فیلتر اختصاصی که خودت میسازی)

  • {{ user.bio | truncate(50) }} (بریدن متن ‌های طولانی)

تله‌ی منطق در قالب (Logic Overload)

خیلی‌ها وسوسه میشوند که توی فایل HTML شروع کنند به نوشتن شرط‌های پیچیده: {% if user.role == 'admin' and user.is_active and not user.is_suspended %}

ایست! اگر چنین چیزی توی قالب داری، یعنی داری راه را اشتباه میروی. در معماری پاک، لایه Use Case یا یک Presenter باید قبلاً این محاسبات را انجام داده باشد و به قالب فقط یک متغیر ساده مثل show_admin_panel: True پاس بدهد. قالب باید "احمق" باشد؛ هر چه قالب احمق ‌تر باشد، تست کردن و تغییر دادنش راحت‌ تر است.

امنیت: سدی در برابر تزریق کد (XSS)

امنیت: سدی در برابر تزریق کد (XSS)

یکی از دلایلی که ما از Jinja2 استفاده میکنیم و سراغ تولید رشته ‌های HTML دستی نمیرویم، امنیت است. Jinja2 به صورت پیش ‌فرض تمام ورودی‌ها را Escape می‌کند. یعنی اگر یک هکر در فیلد  نام کاربری، کدهای <script> مخرب بنویسد، Jinja2 آن را به صورت متن ساده نمایش میدهد و اجازه نمیدهد در مرورگر بقیه اجرا شود. یک مهندس واقعی، امنیت را از همان لایه نمایش جدی میگیرد.

ماکروها (Macros): قطعات لگوی شما

اگر در صفحات مختلف، المان ‌های تکراری (مثل کارت ‌های نمایش محصول یا فرم‌های ورودی) داری، نباید کد HTML آن ‌ها را تکرار کنی. از Macros استفاده کن. ماکرو ها مثل توابع در پایتون هستند؛ یک بار تعریف می‌کنی و هر جا خواستی با ورودی ‌های متفاوت صدایش می‌زنی.

{% macro input(name, value='', type='text') %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}">
{% endmacro %}

{{ input('username') }}
{{ input('password', type='password') }}

نتیجه‌گیری

استفاده درست از Jinja2 در Flask یعنی:

  • تغییر ظاهر بدون دردسر: اگر فردا طراح سایت گفت "کلاس‌های CSS رو کلاً عوض کن"، تو فقط با چند فایل Layout سر و کار داری، نه کل منطق برنامه.

  • کد خوانا: وقتی فایل‌های HTML تو فقط شامل ساختار باشند و منطق پیچیده در آن‌ها نباشد، هر کس دیگری (حتی یک طراح فرانت‌اِند) می‌تواند کدت را بفهمد.

  • پایداری: جدا کردن لایه نمایش باعث می‌شود باگ‌های ظاهری به منطق بیزنس سرایت نکنند.

حالا که یاد گرفتی چطور با Jinja2 نظم را در ظاهر حفظ کنی، یادت باشد که Flask فقط وسیله است؛ معماری درست، امضای تو پای پروژه‌ است.