oruji.github.io
oruji.github.ioPersian Tutorials
ایجاد: 1390/02/01 10:12 - ویرایش: 1396/11/13 19:14
A A

Template ها در جنگو (Django)

در آموزش view و urlconf از این کتاب، دیدیم که کد HTML را می توانیم به صورت یک متن به طور مستقیم درون view بگنجانیم:

def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)

این حالت را (که کد HTML به طور مستقیم درون view قرار بگیرد) به اصطلاح hard-code می نامند، بدین معنا که کد HTML به صورت غیر مستقل داخل کد پایتون قرار دارد و تغییر آن کار ساده ای نخواهد بود.

اگرچه تکنیک فوق برای توضیح و یا شرح نحوه ی کارکرد view در آموزش قبلی مناسب به نظر می آید، اما به دلایل ذکر شده در بالا این ایده ی خوبی نیست که کد HTML به صورت hard-code به طور مستقیم درون view قرار گیرد.

همانطور که ذکر کردیم جدا کردن طراحی صفحه از کد پایتون مربوط به آن بسیار واضح و منطقی است. با استفاده از سیستم template جنگو می توانیم کدهای مربوط به HTML را از کد پایتون جداسازی کنیم، که در این آموزش از کتاب، به این موضوع خواهیم پرداخت.

قواعد Template System

template جنگو یک رشته ای از متن می باشد که برای جدا کردن نمایش یک سند از داده ی خود در نظر گرفته شده است. قالب حفره ها و تکه کدهای (تگ های template) مختلفی را تعریف می کند که نحوه ای که سند باید نمایش داده شود را تنظیم می کند. به طور معمول template ها برای تولید HTML استفاده می شوند، اما template های جنگو به همان اندازه در تولید هر فرمت متنی توانا هستند.

بیایید با یک مثال ساده شروع کرده و آن را مورد بررسی قرار دهیم:

<html> <head><title>Ordering notice</title></head> <body> <h1>Ordering notice</h1> <p>Dear {{ person_name }},</p> <p>Thanks for placing an order from {{ company }}. It's scheduled to ship on {{ ship_date|date:"F j, Y" }}.</p> <p>Here are the items you've ordered:</p> <ul> {% for item in item_list %} <li>{{ item }}</li> {% endfor %} </ul> {% if ordered_warranty %} <p>Your warranty information will be included in the packaging.</p> {% else %} <p>You didn't order a warranty, so you're on your own when the products inevitably stop working.</p> {% endif %} <p>Sincerely,<br />{{ company }}</p> </body> </html>

template فوق یک HTML بنیادی با برخی متغیرها و تگ های template استفاده شده در آن می باشد. بیایید template فوق را مورد بررسی قرار دهیم.

هر قالب جنگو به چندین تگ و فیلتر داخلی (built-in) دسترسی دارد، تعدادی از آن ها در ادامه فصل های کتاب مورد بحث قرار خواهند گرفت. همچنین این امکان وجود دارد که فیلتر و تگ برای خودتان ایجاد کنید؛ که در آموزش template پیشرفته این کتاب بیان خواهد شد.

استفاده از template جنگو

بیایید وارد بحث template جنگو شویم، تا شما نحوه ی کارکرد آن را مشاهده کنید، ولی هنوز نمی خواهیم قالب جنگو را با view هایی که در فصل گذشته ساخته شد به هم مرتبط کنیم. هدف در اینجا این است که با نحوه ی کار template جنگو، مستقل از دیگر بخش ها آشنا شوید. (به عبارت دیگر: به طور معمول شما template جنگو را همراه با یک view استفاده خواهید کرد، ولی می خواهیم این موضوع را روشن کنیم که template جنگو تنها کتابخانه ی پایتون می باشد که شما می توانید آن را در هرجایی استفاده کنید، نه فقط در view های جنگو.)

در اینجا ابتدایی ترین راه که می تونید قالب جنگو را در کد پایتون استفاده کنید آمده است:

ساختن شیء Template از طریق ایجاد کد قالب به صورت رشته.

فراخوانی متد render() از شیء Template با دادن یک مجموعه ای از متغیرها (the context). این متد قالب را به صورت رشته ی کامل با تمام متغیرها و تگ های قالب بر می گرداند.

به کد زیر توجه کنید:

>>> from django import template >>> t = template.Template('My name is {{ name }}.') >>> c = template.Context({'name': 'Adrian'}) >>> print t.render(c) My name is Adrian. >>> c = template.Context({'name': 'Fred'}) >>> print t.render(c) My name is Fred.

در بخش بعدی جزئیات هر خط از کد بالا شرح داده خواهد شد.

ساختن شیء های template

ساده ترین راه برای ساختن شیء Template به طور مستقیم به عنوان نمونه ذکر کردن آن می باشد. کلاس Template درون ماژول django.template می باشد و سازنده ی (cunstructor) آن یک آرگومان دریافت می کند که کد خام template می باشد. بیایید نمونه آن را درون interactive interpreter پایتون مشاهده کنیم.

درون دایرکتوری mysite ساخته شده توسط دستور django-admin.py startproject (بیان شده در شروع کار جنگو)، دستور python manage.py shell را تایپ کرده و interactive interpreter را باز کنید.

اجازه دهید با اصول اولیه سیستم template جنگو آشنا شویم:

>>> from django.template import Template >>> t = Template('My name is {{ name }}.') >>> print t

با وارد کردن کد فوق، چیزی شبیه به این مشاهده خواهید کرد:

<django.template.Template object at 0xb7d5f24c>

عبارت 0xb7d5f24c هویت شیء پایتون می باشد که در هر زمان متفاوت می باشد واز حیطه بحث ما خارج می باشد.

هنگامی که یک شیء Template ایجاد می کنید، سیستم template جنگو کد template را به صورت داخلی کامپایل می کند، و شکل بهینه آن برای ارائه دادن (rendering) آماده می شود، اما در صورتیکه کد template شما دارای اشکال باشد، فراخوانی Template() موجب بروز خطا خواهد شد:

>>> from django.template import Template >>> t = Template('{% notatag %}') Traceback (most recent call last): File "<stdin>", line 1, in ? ... django.template.TemplateSyntaxError: Invalid block tag: 'notatag'

در موارد زیر خطای TemplateSyntaxError رخ خواهد داد:

ارائه دادن (rendering) یک Template

هنگامی که شما یک شیء Template دارید، می توانید از طریق یک context به آن داده ارسال کنید. context مجموعه ای از نام متغیرهای template و ارزش های آن ها می باشد. Template با استفاده از context متغیرهای خودش را با ارزش مورد نظر جایگزین کرده و تگ ها را نیز اجرا می کند.

context با کلاس Context در جنگو نشان داده می شود، که درون ماژول django.template قرار دارد. سازنده ی آن یک آرگومان اختیاری دریافت می کند: یک دیکشنری نام های متغیر و ارزش های آن. برای پر کردن template متد render() شیء Template را با context فراخوانی می کنیم:

>>> from django.template import Context, Template >>> t = Template('My name is {{ name }}.') >>> c = Context({'name': 'Stephane'}) >>> t.render(c) u'My name is Stephane.'

نکته ای که باید در اینجا اشاره کنیم این است که مقدار برگشتی (t.render(c یک رشته ی معمولی پایتون نمی باشد، بلکه یک شیء یونیکد است. که با نمایش حرف u در ابتدای آن نشان داده می شود. جنگو در سراسر فریم ورک یا چارچوب به جای رشته ی معمولی پایتون از شیء های یونیکد استفاده می کند. پشتیبانی یونیکد جنگو نسبتااز طیف گسترده ای از حروف برای برنامه های شما بدون زحمت و دردسر پشتیبانی می کند.

نام متغیرها باید با حروف الفبای انگلیسی شروع شوند (A-Z or a-z) و می توانند حاوی حروف الفبا، عدد، خط تیره (_) و نقطه باشند (نقطه ها مورد ویژه ای هستند که بعدا راجع به آن صحبت خواهیم کرد.)، همچنین نام متغیرها به حروف کوچک و بزرگ حساس می باشند.

در اینجا یک مثال از کامپایل template و rendering آن شبیه به مثالی که در ابتدای فصل مشاهده کردید وجود دارد،

>>> from django.template import Template, Context >>> raw_template = """<p>Dear {{ person_name }},</p> ... ... <p>Thanks for placing an order from {{ company }}. It's scheduled to ... ship on {{ ship_date|date:"F j, Y" }}.</p> ... ... {% if ordered_warranty %} ... <p>Your warranty information will be included in the packaging.</p> ... {% else %} ... <p>You didn't order a warranty, so you're on your own when ... the products inevitably stop working.</p> ... {% endif %} ... ... <p>Sincerely,<br />{{ company }}</p>""" >>> t = Template(raw_template) >>> import datetime >>> c = Context({'person_name': 'John Smith', ... 'company': 'Outdoor Equipment', ... 'ship_date': datetime.date(2009, 4, 2), ... 'ordered_warranty': False}) >>> t.render(c) u"<p>Dear John Smith,</p>\n\n<p>Thanks for placing an order from Outdoor Equipment. It's scheduled to\nship on April 2, 2009.</p>\n\n\n<p>You didn't order a warranty, so you're on your own when\nthe products inevitably stop working.</p>\n\n\n<p>Sincerely,<br />Outdoor Equipment </p>"

اجازه دهید کد فوق را مورد بررسی قرار دهیم:

مسائل فوق اصول استفاده از template system جنگو می باشد: نوشتن یک رشته ی template، ساختن شیء Template، ساختن Context و فراخوانی متد render().

Context های چندگانه در یک Template

با یک شیء Template می توانید چندین context را ارائه دهید. برای مثال:

>>> from django.template import Template, Context >>> t = Template('Hello, {{ name }}') >>> print t.render(Context({'name': 'John'})) Hello, John >>> print t.render(Context({'name': 'Julie'})) Hello, Julie >>> print t.render(Context({'name': 'Pat'})) Hello, Pat

هر گاه مانند مثال فوق از template همسان برای چندین context استفاده می کنید ، بسیار بهینه تر می باشد اگر یک مرتبه یک شیء Template ساخته و سپس متد render() را برای چند بار فراخوانی کنید:

# Bad for name in ('John', 'Julie', 'Pat'): t = Template('Hello, {{ name }}') print t.render(Context({'name': name})) # Good t = Template('Hello, {{ name }}') for name in ('John', 'Julie', 'Pat'): print t.render(Context({'name': name}))

تجزیه ی template جنگو کاملا سریع می باشد. در پشت صحنه بیشترین تجزیه در جنگو از طریق فراخوانی یک regular expression می باشد. این متضاد با موتور های template ای می باشد که پایه اساس آنها XML باشد، چرا که بسیار کند تر از موتور template جنگو می باشند.

متغیرهای دیگر قابل ارسال به Context

مثال های آورده شده تاکنون، یک مقدار ساده را به context ها ارسال کرده اند که به غیر مثال datetime.date غالبا رشته بوده اند. در صورتی که template system جنگو با ظرافت خاصی تعداد بیشتری از داده های با ساختار پیچیده را مانند لیست ها، دیکشنری ها و شیء های ساخته شده را نیز کنترل می کند.

کلید گذشتن از داده های با ساختار پیچیده در template های جنگو حرف نقطه ( . ) می باشد، با استفاده از نقطه می توان به کلیدهای دیکشنری، attribute ها، متد ها و اندیس های یک شیء نیز دسترسی داشت.

بهترین توضیح استفاده از چند مثال می باشد. برای نمونه، فرض کنید شما یک دیکشنری پایتون را به یک template ارسال کرده اید. برای دسترسی به مقادیر دیکشنری مورد نظر با کلید دیکشنری از یک نقطه استفاده کنید:

>>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name }} is {{ person.age }} years old.') >>> c = Context({'person': person}) >>> t.render(c) u'Sally is 43 years old.'

به طور مشابه، نقطه ها همچنین اجازه می دهند به attribute های شیء نیز دسترسی پیدا کنید. برای مثال، شیء datetime.date پایتون دارای attribute های year، month و day می باشد، می توان با استفاده از یک نقطه به attribute های آن در template جنگو دسترسی پیدا کرد:

>>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1993, 5, 2) >>> d.year 1993 >>> d.month 5 >>> d.day 2 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.') >>> c = Context({'date': d}) >>> t.render(c) u'The month is 5 and the year is 1993.'

در مثال زیر از یک کلاس ساخته شده استفاده شده است که نشان می دهد از نقطه ها می توان جهت دسترسی به شیء های دلخواه نیز استفاده کرد:

>>> from django.template import Template, Context >>> class Person(object): ... def __init__(self, first_name, last_name): ... self.first_name, self.last_name = first_name, last_name >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.') >>> c = Context({'person': Person('John', 'Smith')}) >>> t.render(c) u'Hello, John Smith.'

از طریق نقطه ها همچنین می توانند به متدهای درون یک شیء نیز دسترسی پیدا کرد. برای مثال هر رشته ی پایتون، دارای متدهای upper() و isdigit() می باشد، و می توان آن ها را در template جنگو فراخوانی و استفاده کرد:

>>> from django.template import Template, Context >>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}') >>> t.render(Context({'var': 'hello'})) u'hello -- HELLO -- False' >>> t.render(Context({'var': '123'})) u'123 -- 123 -- True'

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

همچنین نقطه ها برای دسترسی به اندیس های لیست نیز استفاده می شوند، برای مثال:

>>> from django.template import Template, Context >>> t = Template('Item 2 is {{ items.2 }}.') >>> c = Context({'items': ['apples', 'bananas', 'carrots']}) >>> t.render(c) u'Item 2 is carrots.'

اندیس های منفی لیست را در template نمی توان استفاده کرد، برای مثال، متغیر {{ items.-1 }} موجب بروز خطای TemplateSyntaxError خواهد شد.

کاربرد نقطه ها در template را می توان بدین شکل خلاصه کرد: هنگامی که template system با یک نقطه در مقابل نام یک متغیر برخورد می کند، به دنبال مسائل زیر جستجو خواهد کرد:

نقطه ها می توانند به صورت تودرتو نیز استفاده شوند. به عنوان نمونه،مثال زیر از عبارت {{ person.name.upper }} استفاده کرده است که ابتدا درون یک دیکشنری به جستجو می پردازد (person['name']) سپس یک متد را فراخوانی می کند (upper()):

>>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name.upper }} is {{ person.age }} years old.') >>> c = Context({'person': person}) >>> t.render(c) u'SALLY is 43 years old.'

فراخوانی متد و رفتار آن

فراخوانی متد کمی پیچیده تر از دیگر انواع جستجو می باشد. در زیر مواردی که باید به خاطر داشته باشیم بیان شده است:

نحوه ی کنترل متغیرهای نا معتبر

به صورت پیشفرض، اگر یک متغیر وجود نداشته باشد، template system آن را به صورت یک رشته ی خالی ارائه می دهد. به عنوان مثال:

>>> from django.template import Template, Context >>> t = Template('Your name is {{ name }}.') >>> t.render(Context()) u'Your name is .' >>> t.render(Context({'var': 'hello'})) u'Your name is .' >>> t.render(Context({'NAME': 'hello'})) u'Your name is .' >>> t.render(Context({'Name': 'hello'})) u'Your name is .'

سیستم template بجای بروز خطا، آرام از کنار آن می گذرد. در صورت بروز خطا در این مورد برنامه به دلیل مچ نبودن حروف بزرگ و کوچک از روال عادی خارج می شود، در دنیای واقعی، برای یک وب سایت غیر قابل قبول است که به دلیل یک خطای نوشتاری در یک template کوچک همه چیز غیر قابل دسترس شده و برنامه متوقف شود.

بازی با شیء های Context

در اغلب مواقع، شیء های Context را با ارسال داده ی دیکشنری به آن تعریف می کنند. می توان ایتم های شیء Context را بعد از تعریف نیز مانند دیکشنری استاندارد پایتون حذف یا اضافه کرد:

>>> from django.template import Context >>> c = Context({"foo": "bar"}) >>> c['foo'] 'bar' >>> del c['foo'] >>> c['foo'] Traceback (most recent call last): ... KeyError: 'foo' >>> c['newvariable'] = 'hello' >>> c['newvariable'] 'hello'

تگ ها و فیلترهای اولیه ی Template

همانطور که گفته شد، سیستم template جنگو تعدادی تگ ها و فیلترهای داخلی را با خود حمل می کند. در این بخش خلاصه ای از متداول ترین تگ ها و فیلترها را مورد بررسی قرار خواهیم داد.

تگ if/else

تگ {% if %} یک متغیر را مورد ارزیابی قرار می دهد، و در صورتی که مقدار متغیر True (مانند وجود داشتن، خالی نبودن، و مقدار False نبودن) بود، سیستم template جنگو هر آنچه را که بین تگ {% if %} و {% endif %} باشد را نمایش خواهد داد، مانند:

{% if today_is_weekend %} <p>Welcome to the weekend!</p> {% endif %}

استفاده از یک تگ {% else %} اختیاری می باشد:

{% if today_is_weekend %} <p>Welcome to the weekend!</p> {% else %} <p>Get back to work.</p> {% endif %}

تگ {% if %} عبارات and، or و not را برای آزمودن چندین متغیر، یا منفی کردن متغیر داده شده قبول می کند. به عنوان مثال:

{% if athlete_list and coach_list %} Both athletes and coaches are available. {% endif %} {% if not athlete_list %} There are no athletes. {% endif %} {% if athlete_list or coach_list %} There are some athletes or some coaches. {% endif %} {% if not athlete_list or coach_list %} There are no athletes or there are some coaches. {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %}

تگ های {% if %} اجازه ی نمی دهند عبارات and و or در یک تگ همسان استفاده شوند، دلیل آن است که ترتیب محاسبه ی آن ها مبهم خواهد بود. برای عنوان مثال کد زیر نا معتبر است:

{% if athlete_list and coach_list or cheerleader_list %}

استفاده از پرانتز برای کنترل کردن ترتیب عملکردها در سیستم template پشتیبانی نمی شود. در صورتیکه نیاز به استفاده از پرانتز بود، می توان اعمال منطقی را بیرون از template انجام داده و نتیجه را به عنوان متغیر template ارسال کرد، و یا آنکه از تگهای {% if %} به صورت تودرتو استفاده کرد. مانند:

{% if athlete_list %} {% if coach_list or cheerleader_list %} We have athletes, and either coaches or cheerleaders! {% endif %} {% endif %}

استفاده از چند عملگر یکسان در یک تگ مجاز می باشد، ولی نمی توان عملگرهای متفاوت را بدین شکل استفاده کرد، برای مثال کد زیر معتبر می باشد:

{% if athlete_list or coach_list or parent_list or teacher_list %}

تگی با نام {% elif %} وجود ندارد. می توان از تگ های {% if %} تودرتو برای این کار استفاده کرد:

{% if athlete_list %} <p>Here are the athletes: {{ athlete_list }}.</p> {% else %} <p>No athletes are available.</p> {% if coach_list %} <p>Here are the coaches: {{ coach_list }}.</p> {% endif %} {% endif %}

اطمینان حاصل کنید که هر تگ {% if %} با یک تگ {% endif %} بسته شده است. در غیر اینصورت خطای TemplateSyntaxError ایجاد خواهد شد.

تگ for

تگ {% for %} اجازه می دهد تا به ترتیب در سراسر ایتم های یک لیست یا ... چرخ بزنید. همانند عبارت for در پایتون؛ for X in Y، Y لیست مورد نظر می باشد و X در هر نوبت از حلقه یکی از ایتم های Y می باشد. سیستم template در هر بار، هر چیزی که بین {% for %} و {% endfor %} باشد را اجرا می کند.

برای مثال، می توانید از کد زیر یک لیست از ورزشکاران را که به صورت متغیر athlete_list داده شده است را نمایش دهید:

<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>

اضافه کردن کلمه ی reversed موجب می شود که حلقه به صورت بر عکس جریان پیدا کند:

{% for athlete in athlete_list reversed %} ... {% endfor %}

می توان از تگ های {% for %} به صورت تودرتو نیز استفاده کرد:

{% for athlete in athlete_list %} <h1>{{ athlete.name }}</h1> <ul> {% for sport in athlete.sports_played %} <li>{{ sport }}</li> {% endfor %} </ul> {% endfor %}

می توان از الگوی کد زیر برای بررسی کردن اندازه ی لیست استفاده کرد، همچنین در صورت خالی بودن لیست، می توان یک پیام را نمایش داد:

{% if athlete_list %} {% for athlete in athlete_list %} <p>{{ athlete.name }}</p> {% endfor %} {% else %} <p>There are no athletes. Only computer programmers.</p> {% endif %}

به دلیل آنکه الگوی فوق بسیار رایج می باشد، تگ for از یک تگ {% empty %} پشتیبانی می کند که به شما اجازه می دهد در صورت خالی بود لیست آنچرا که می خواهید تعریف کنید. مثال زیر معادل کد قبلی می باشد:

{% for athlete in athlete_list %} <p>{{ athlete.name }}</p> {% empty %} <p>There are no athletes. Only computer programmers.</p> {% endfor %}

در سیستم template از عبارت break پشتیبانی نمی شود، بدین معنی که عبارتی برای شکستن روال عادی حلقه وجود ندارد. برای انجام چنین کاری می توان متغیر لیست را طوری تغییر داد که تنها حاوی مقادیری باشد که می خواهیم حلقه در آن بچرخد. به طور مشابه از عبارت continue نیز پشتیبانی نمی شود (از عبارت continue در پایتون برای انتقال حرکت حلقه به طور ناگهانی به ابتدای حلقه استفاده می شود.) (در همین فصل، در بخش فلسفه ی محدودیت ها دلیل محدودیت های فوق را درخواهید یافت.)

داخل هر حلقه ی {% for %}، می توانید به یک متغیر template با نام forloop دسترسی پیدا کنید. این متغیر دارای attribute هایی می باشد که دارای اطلاعاتی در مورد حرکت حلقه می باشند.

متغیر forloop تنها در داخل حلقه ها در دسترس می باشد. بعد از آنکه template به تگ {% endfor %} می رسد، forloop از بین می رود.

تگ ifequal/ifnotequal

سیستم template جنگو به طور عمد یک زبان برنامه نویسی کامل نمی باشد، در نتیجه اجازه ی اجرای عبارت های دلخواه پایتون را نمی دهد. (برای اطلاعات بیشتر نسبت به این محدودیت به بخش فلسفه ی محدودیت ها در همین بخش مراجعه کنید.) با این وجود، سیستم template جنگو برای مقایسه ی دو مقدار و نمایش چیزی در صورت مساوی بودن آن ها امکانات کاملی را پشتیبانی می کند (برای این منظور تگ {% ifequal %} در جنگو پیش بینی شده است.)

تگ {% ifequal %} دو مقدار را با هم مقایسه می کند و در صورت مساوی بودن، هر آنچه که مابین {% ifequal %} و {% endifequal %} می باشد را نمایش می دهد.

مثال زیر دو متغیر user و currentuser را مقایسه می کند:

{% ifequal user currentuser %} <h1>Welcome!</h1> {% endifequal %}

همچنین می توان برای مقایسه ی دو مقدار از رشته ی خام درون تک کوتیشن و یا دابل کوتیشن استفاده کرد:

{% ifequal section 'sitenews' %} <h1>Site News</h1> {% endifequal %} {% ifequal section "community" %} <h1>Community</h1> {% endifequal %}

درست مثل {% if %}، تگ {% ifequal %} نیز به طور اختیاری از تگ {% else %} پشتیبانی می کند:

{% ifequal section 'sitenews' %} <h1>Site News</h1> {% else %} <h1>No News Here</h1> {% endifequal %}

تنها متغیرهای template مانند؛ رشته ها، اعداد صحیح، و اعداد اعشاری می توانند به عنوان آرگومان {% ifequal %} قرار بگیرند. مثال های زیر معتبر می باشند:

{% ifequal variable 1 %} {% ifequal variable 1.23 %} {% ifequal variable 'foo' %} {% ifequal variable "foo" %}

نوع داده های دیگر از قبیل دیکشنری ها، لیست ها، و Boolean، برای {% ifequal %} مجاز نمی باشند. مثال های زیر نامعتبر می باشند:

{% ifequal variable True %} {% ifequal variable [1, 2, 3] %} {% ifequal variable {'key': 'value'} %}

کامنت ها

تنها در HTML و پایتون، زبان template جنگو اجازه می دهد از کامنت ها استفاده شود. برای طراحی یک کامنت از {# #} استفاده می شود:

{# This is a comment #}

هنگامی که template اجرا می شود، کامنت ها هیچ خروجی ای نخواهند داشت.

از تگ فوق نمی توان برای کامنت های چند خطی استفاده کرد. مثال زیر به عنوان کامنت در نظر گرفته نمی شود و مانند دیگر عبارت template به حساب می اید:

This is a {# this is not a comment #} test.

در صورتیکه می خواهید از کامنت های چند خطی استفاده کنید؛ بایستی از تگ {% template comment %} مانند زیر استفاده کرد:

این یک کامنت چند خطی است.{% comment %} {% endcomment %}

فیلتر ها

همانطور پیش تر در این فصل توضیح داده شد، فیلترها روش های ساده ای برای تغییر مقدار متغیرها قبل از نمایش آن ها می باشند. فیلتر ها مانند زیر از علامت پایپ (|) استفاده می کنند:

{{ name|lower }}

کد فوق مقدار متغیر {{ name }} را بعد از عبور از فیلتر lower به حروف کوچک انگلیسی تبدیل می کند.

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

{{ my_list|first|upper }}

بعضی فیلترها آرگومان نیز دریافت می کنند. آرگومان فیلتر بعد از علامت (:) و همواره داخل دابل کوتیشن مانند مثال زیر قرار می گیرد:

{{ bio|truncatewords:"30" }}

مثال فوق 30 لغت اول متغیر bio را نمایش می دهد.

در زیر تعداد از مهمترین فیلتر ها توضیح داده شده اند:

فلسفه ی محدودیت ها

اکنون که تا حد زیادی با زبان template جنگو آشنا شده اید، وقت آن رسیده است که به برخی از محدودیت های عمدی موجود در این زبان، به همراه فلسفه ی این که چرا این زبان به این شکل کار می کند اشاره کنیم.

قواعد زبان template جنگو ،بیشتر از هر جزء دیگری از برنامه های وب، بسیار خصوصی بوده و انتخاب های برنامه نویس بسیار گسترده می باشد. حقیقتی است که پایتون دارای پشتیبانی از ده ها زبان template سورس باز می باشد. که احتمالا هر کدام به این دلیل ساخته شده اند که توسعه دهنده معتقد بر این بوده است که زبان های template موجود، کافی نمی باشند. (در حقیقت، این فرمان عبور، برای یک توسعه دهنده پایتون، برای نوشتن زبان template خودش می باشد، اگر تاکنون همچین کاری نکرده اید، می توانید آن را امتحان، زیرا یک تمرین جالب می باشد.)

با در نظر گرفتن این موضوع، جالب است این را بدانید که جنگو نیازی به استفاده از زبان template آن ندارد؛ یعنی می توان از هر زبان template دیگر نیز استفاده کرد. زیرا جنگو برای این در نظر گرفته شده است که یک فریم ورک یا چارچوب وب full-stack، برای تهیه ی تمام قسمت های ضروری برای توسعه دهندگان باشد تا یک تولید کننده باشند، خیلی وقت ها استفاده از سیستم template جنگو (Django) مناسب تر از کتابخانه های templte دیگر پایتون می باشد، ولی این یک نیازمندی موکد نمی باشد. همانطور که در بخش اینده ی این آموزش از کتاب، "استفاده از template ها در view" مشاهده خواهید کرد، استفاده از زبان های template دیگر بسیار آسان می باشد.

واضح است که ترجیح می دهیم از خود زبان template جنگو استفاده کنیم. template system دارای اصولی نسبت به نحوه ی توسعه ی وب انجام شده در World Online و تجربیات متعدد سازندگان جنگو می باشد. در زیر به تعدادی از این فلسفه ها اشاره خواهیم کرد:

استفاده از template ها در view

اصول اولیه ی استفاده از template system را آموختیم؛ اجازه دهید از این دانش برای ساخت view استفاده کنیم. تابع current_datetime را در ماژول mysite.views که در فصل گذشته ساخته شد را دوباره فراخوانی کنید:

from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)

اجازه دهید view فوق را با استفاده از سیستم template جنگو تغییر دهیم. در ابتدا ممکن است فکر کنید، باید کاری شبیه به کد فوق را انجام دهید:

from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = Template("<html><body>It is now {{ current_date }}.</body></html>") html = t.render(Context({'current_date': now})) return HttpResponse(html)

مطمئنا از template system استفاده خواهیم کرد، ولی روش فوق مشکلات که در ابتدای فصل به آن اشاره کردیم را حل نمی کند. به عنوان مثال، template همچنان درون کد پایتون می باشد. می توان مشکل فوق را با جدا کردن template درون فایلی دیگر حل کرد، به طوری که فایل مذکور درون view بار گذاری شود.

ممکن است ابتدا اینطور به نظر برسد که template را درون جایی روی سیستم ذخیره کردن و با استفاده از توابع داخلی پایتون محتویات فایل مورد نظر را بخوانید. در مثال زیر فرض شده است که template درون فایل /home/djangouser/templates/mytemplate.html ذخیره شده است:

from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() # Simple way of using templates from the filesystem. # This is BAD because it doesn't account for missing files! fp = open('/home/djangouser/templates/mytemplate.html') t = Template(fp.read()) fp.close() html = t.render(Context({'current_date': now})) return HttpResponse(html)

روش فوق نیز با توجه به معایبی که در ادامه بیان می کنیم، روش مناسبی نمی باشد:

برای حل کردن موارد فوق، از بار گذاری template و دایرکتوری های آن استفاده می شود.

بار گذاری Template

جنگو با هدف حذف کردن کدهای اضافه در برنامه هنگام فراخوانی و همچنین درون template، برای بارگذاری template ها یک API بسیار مناسب و قدرتمند تهیه کرده است.

به منظور استفاده از API بار گذاری template، ابتدا می بایست به فریم بگویید که template ها را در کجا ذخیره خواهید کرد. برای انجام چنین کاری نیازمند فایل settings می باشید. (در فصل گذشته هنگام معرفی تنظیم ROOT_URLCONF، در مورد فایل settings.py صحبت شد.)

اگر از ابتدا کتاب را دنبال کرده اید، فایل settings.py را باز کرده و تنظیم TEMPLATE_DIRS را پیدا کنید. تنظیم فوق، یک تاپل خالی که احتمالا حاوی برخی کامنت های پیشفرض که به صورت خودکار تولید شده است، می باشد:

TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. )

تنظیم فوق به مکانیسم بار گذاری template جنگو می گوید که باید در کجا به دنبال template ها بگردد. مسیر و دایرکتوری را که می خواهید template های خود را ذخیره کنید مانند مثال زیر درون TEMPLATE_DIRS اضافه کنید:

TEMPLATE_DIRS = ( '/home/django/mysite/templates', )

توجه به چند نکته ضروری است:

بعد از تنظیم TEMPLATE_DIRS، گام بعدی تغییر کد view می باشد که باید از بار گذاری template به جای استفاده مستقیم template، استفاده کرد. باز می گردیم به تابع current_datetime، و آن را مانند زیر تغییر می دهیم:

from django.template.loader import get_template from django.template import Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = get_template('current_datetime.html') html = t.render(Context({'current_date': now})) return HttpResponse(html)

در مثال فوق، از تابع django.template.loader.get_template() بجای بارگذاری template از سیستم به صورت دستی استفاده شده است. تابع get_template() نام template را به عنوان آرگومان دریافت کرده، و محلی را در سیستم template در آن وجود دارد را پیدا کرده، آن را باز کرده و و یک شیء template کامپایل شده را بر می گرداند.

template مورد نظر در مثال فوق current_datetime.html می باشد، ولی هیچ چیز خاصی درباره ی پسوند .html وجود ندارد. شما می توانید هر پسوندی که می خواهید برای آن قرار دهید، و یا حتی می توانید پسوند فایل را کلا حذف کنید.

برای تعیین مکان template در روی سیستم، تابع get_template() مسیر فایل را که در TEMPLATE_DIRS وجود دارد را با نام template که به آن ارسال می کنید ترکیب می کند. به عنوان مثال اگر TEMPLATE_DIRS حاوی آدرس /home/django/mysite/templates باشد، تابع get_template() مثال فوق فایل زیر را جستجو خواهد کرد.

/home/django/mysite/templates/current_datetime.html

در صورتیکه تابع get_template() موفق به یافتن template با نام داده شده نشود، خطای TemplateDoesNotExist ایجاد خواهد شد. برای دیدن خطای فوق سرور جنگو را با دستور python manage.py runserver درون دایرکتوری پروژه جنگو اجرا کنید. سپس مرورگر خود را باز کرده و به آدرس مورد نظر برای مثال http://127.0.0.1:8000/time/ بروید. با فرض اینکه تنظیم DEBUG به صورت True می باشد و هنوز template مورد نظر یعنی current_datetime.html ساخته نشده است، شما باید یک صفحه خطای جنگو را با نام TemplateDoesNotExist مشاهده کنید.

صفحه ی خطای فوق همانند صفحه ای است که در آموزش view و urlconf جنگو توضیح داده شد، تنها با یک قسمت اطلاعات اضافه تر: بخش Template-loader postmortem. این بخش به شما می گوید که جنگو کدام template ها را بار گذاری کرده است، و همچنین دلیل رد کردن template ها را نیز در بر می گیرد (مانند File does not exist). این اطلاعات هنگامی که شما می خواهید خطاهای بارگذاری template را بر طرف کنید بسیار با ارزش می باشند.

در پایان می بایست current_datetime.html را درون دایرکتوری template خود ساخته و کد زیر را درون آن قرار دهید:

<html><body>It is now {{ current_date }}.</body></html>

صفحه را ذخیره کرده و صفحه ی مرورگر خود را به اصطلاح refresh کنید، شما می بایست صفحه تولید شده حاوی زمان و تاریخ فعلی خود را مشاهده کنید.

تابع render_to_response()

همانطور که قبلا اشاره کردیم، بارگذاری یک template شامل پر کردن یک Context و بر گرداندن نتیجه ی یک template توسط یک شیء HttpResponse، می باشد. همانطور که گفته شد در روش فوق با استفاده از get_template() به جای template های مستقیم و یا آدرس درون کد، توانستیم کد خود را بهینه تر کنیم. ولی همچنان نیاز به یک حرکت زیبا برای بهینه تر کردن کد وجود دارد. جنگو یک میانبر (shortcut) ارائه می دهد که از طریق آن تنها می توان با یک خط کد template را بار گذاری کرده، آن را ارائه داده و یک HttpResponse را بر گردانید.

این میانبر یک تابع است که render_to_response() نام دارد، که در ماژول django.shortcuts قرار دارد. اغلب اوقات شما بجای بارگذاری template ها و ساختن Context و شیء ها HttpResponse به صورت دستی از render_to_response() استفاده خواهید کرد، مگر آنکه کارفرای شما بر اساس مجموع خط های موجود در کدی که نوشته اید نسبت به کار شما تصمیم گیری کند.

در زیر تابع بهینه شده ی current_datetime که با استفاده از render_to_response() دوباره نویسی شده است را مشاهده می کنید:

from django.shortcuts import render_to_response import datetime def current_datetime(request): now = datetime.datetime.now() return render_to_response('current_datetime.html', {'current_date': now})

آن چه که تغییر پیدا کرده است:

اولین آرگومان تابع render_to_response() نام template مورد استفاده می باشد. دومین آرگومان در صورت ارسال، باید یک دیکشنری باشد که جهت ساختن Context برای template استفاده می شود. در صورتیکه دومین آرگومان را ارسال نکنید، render_to_response() از یک دیکشنری خالی استفاده می کند.

تکنیک locals()

آخرین تابع current_datetime نوشته شده ملاحظه کنید:

def current_datetime(request): now = datetime.datetime.now() return render_to_response('current_datetime.html', {'current_date': now})

درون یک برنامه شما چندین بار مانند مثال فوق، مقادیری را حساب کرده و درون متغیرهایی ذخیره می کنید (مانند متغیر now در کد قبلی)، و متغیرها را به template مورد نظر ارسال می کنید. برنامه نویسان راحت طلب باید توجه داشته باشند که این کمی اضافه کاری است که باید متغیرها موقت ساخته و نام گذاری کنند و نام آن ها را برای template ارسال کنند. نه تنها این کار زائدی می باشد، بلکه تایپ اضافی درون برنامه نیز می باشد.

پس اگر شما جزء آن دسته از برنامه نویسان راحت طلب می باشید که مایلند کد خود را کوتاه و مختصر نگه دارند، می توانید از یک تابع داخلی پایتون به نام locals() استفاده کنید. این تابع یک دیکشنری بر می گرداند که حاوی نام تمام متغیرهای محلی و ارزش هایشان می باشد، متغیرهای محلی به متغیرهایی گفته می شود که داخلی محدوده ی فعلی تعریف شده باشند. در نتیجه، view قبلی را می تواند به صورت زیر بازنویسی کرد:

def current_datetime(request): current_date = datetime.datetime.now() return render_to_response('current_datetime.html', locals())

در مثال فوق، بجای تعیین کردن دیکشنری context به صورت دستی همانند قبل، مقدار locals() ارسال شده است، که شامل تمام متغیرهای تعریف شده در آن نقطه از اجرای تابع می باشد. در نتیجه، متغیر now به current_date تغییر نام پیدا کرده است، زیرا درون template نیز نام current_date معرفی شده است. در مثال فوق، locals() یک پیشرفت عظیم را ارائه نمی کند، ولی این تکنیک می تواند شما را از شر تایپ کردن زیاد خلاص می کند، البته اگر شما چندین متغیر template برای تعریف دارید و یا اینکه کمی تنبل هستید.

چیزی که باید در مورد استفاده از locals() مراقب آن باشید این است که این تابع حاوی تمام متغیرهای محیطی و شاید خیلی بیشتر از آنچه شما واقعا نیاز دارید می باشد، در مثال قبلی، locals() همچنین حاولی request نیز می باشد. البته استفاده از locals() به برنامه و نوع استفاده شما بستگی دارد.

دایرکتوری های زیر مجموعه در get_template()

ذخیره ی تمام template ها درون یک دایرکتوری می تواند کمی سنگین باشد. ممکن است بخواهید template ها را درون دایرکتوری های زیر مجموعه ی دایرکتوری template قرار داهید.

ذخیره ی template ها درون دایرکتوری های زیرمجموعه ی دایرکتوری template بسیار آسان می باشد. تنها کافیست درون get_template()، نام دایرکتوری زیرمجموعه و بعد از آن یک علامت (/) و بعد نام template را قرار دهید:

t = get_template('dateapp/current_datetime.html')

همچنین می توانید از این امکان در تابع render_to_response() نیز استفاده کنید بدین صورت که اعمال فوق را درون اولین پارامتر این تابع قرار می دهید:

return render_to_response('dateapp/current_datetime.html', {'current_date': now})

هیچ محدودیتی نسبت به تعداد دایرکتوری های زیر مجموعه ی استفاده شده وجود ندارد و می توانید در صورت نیاز از هر تعداد از آن ها استفاده کنید.

تگ include

اکنون که مکانیزم بارگذاری template شرح داده شده است، می توان یک تگ داخلی template و مزایای آن را معرفی کرد: {% include %}. این تگ اجازه می دهد تا محتویات template های دیگر را درون template فعلی وارد کرد. آرگومان این تگ باید نام template ای باشد که می خواهید وارد template فعلی بکنید. همچنین این آرگومان می تواند یک متغیر و یا کد مستقیم HTML باشد که درون تک کتیشن یا دابل کتیشن قرار دارد. زمانی که یک کد همسان درون چندین template وجود دارد، می توان برای جلوگیری از تکرار کد نویسی از تگ include استفاده کرد.

هر دو مثال زیر برای include معتبر می باشند:

{% include 'nav.html' %} {% include "nav.html" %}

مثال زیر محتویات template، includes/nav.html را وارد template خواهد کرد:

{% include 'includes/nav.html' %}

مثال زیر محتویات template ای را که نامش درون متغیر template_name ذخیره شده است را وارد می کند:

{% include template_name %}

همانند get_template()، نام فایل template با اضافه شدن به مسیر دایرکتوری template که در تنظیم TEMPLATE_DIRS قرار دارد تعیین می شود.

template های وارد شده با context مربوط به template که آن ها را وارد کرده است ارزیابی می شوند. به عنوان مثال دو template زیر را ملاحظه کنید.

# mypage.html <html> <body> {% include "includes/nav.html" %} <h1>{{ title }}</h1> </body> </html> # includes/nav.html <div id="nav"> You are in: {{ current_section }} </div>

در صورتیکه که شما mypage.html را با یک context حاوی current_section ارائه (render) کنید، متغیر template وارد شده همانطور که انتظار خواهید داشت در دسترس خواهد بود.

در صورتیکه یک تگ {% include %}، template ای را وارد کند که وجود نداشته باشد، یکی از حالت های زیر پیش می اید:

ارث بری در Template

مثال های template ای که تاکنون استفاده شده است از نظر محتوی خیلی مختصر و کم حجم بوده اند. ولی در دنیای واقعی، شما تز template system جنگو برای ساختن صفحات HTML با حجم و محتویات بسیار گسترده استفاده خواهید کرد. در این صورت با یک مشکل مشترک و عمومی توسعه ی وب رو به رو خواهید بود: چگونه می توان از بوجود آمدن صفحات و کدها تکراری در ساخت صفحات وب که اجتناب ناپذیر است جلوگیری کرد؟

روش عمومی برای حل این مشکل استفاده از incude های سمت سرور می باشد، دستورالعمل هایی که شما می توانید داخل صفحه ی خود صفحات دیگر را نیز وارد کنید. در واقع، جنگو از این روش با استفاده از تگ template {% include %} پشتیبانی می کند که توضیح آن پیش تر داده شده است. ولی روش بهتری برای حل این مشکل وجود دارد که یکی از استراتژی های مطلوب جنگو به شمار می اید که "ارث بری template" نام دارد.

در واقع، ارث بری template، این اجازه را می دهد که یک اسکلت بندی پایه و اولیه از template بسازید که حاوی تمام بخش های عمومی می باشد. این بخش ها به صورت block ها تعریف می شوند و template هایی که از آن template پدر، ارث بری می کنند می توانند آن بخش ها را دوباره نویسی و یا به اصطلاح overwrite کنند.

به مثال زیر توجه کنید، که همان بر روی template قبلی یعنی current_datetime.html موضوع فوق را توضیح داده است:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>The current time</title> </head> <body> <h1>My helpful timestamp site</h1> <p>It is now {{ current_date }}.</p> <hr> <p>Thanks for visiting my site.</p> </body> </html>

تا اینجا مشکلی وجود نخواهد داشت، ولی چه اتفاقی می افتد اگر بخواهید یک template برای یک view دیگر مانند تابع hours_ahead که در آموزش view و urlconf جنگو وجود داشت ایجاد کنید؟ در صورتیکه بخواهید یک template کامل دیگر برای view دوم بسازید، چیزی شبیه به مثال زیر خواهد بود:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>Future time</title> </head> <body> <h1>My helpful timestamp site</h1> <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> <hr> <p>Thanks for visiting my site.</p> </body> </html>

کاملا واضح هست که مقدار زیادی کد تکراری در دو مثال فوق وجود دارد. تصور کنید اگر بخواهید صفحات بیشتری داشته باشید مانند یک سایت بزرگ که حاوی style sheet ها و یا مقادیر زیادی کد Java Script می باشد چه خواهید کرد؟

راهکار include سمت سرور برای این مشکل راه حل مناسبی نمی باشد، چرا که به عنوان مثال برای قسمت بالایی کد شما یک template با نام header.html خواهید داشت:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head>

و برای قسمت پایین کد یک template با نام footer.html مانند مثال زیر:

<hr> <p>Thanks for visiting my site.</p> </body> </html>

با یک استراتژی مانند ارث بری هر دو قسمت بسیار آسان پیاده سازی خواهند شد. در مثال فوق هر دو صفحه تیتر صفحه را نشان می دهند (<h1>My helpful timestamp site</h1>) و نمی توان آن را درون header.html قرار داد، چرا که <title> در هر صفحه متفاوت از صفحه ی دیگر خواهد بود. و اگر <titile> درون header.html قرار داده می شد، دیگر امکان تغییر آن برای هر صفحه به طور جدا گانه امکان پذیر نبود و تمام صفحات می بایست یک <title> را نمایش بدهند.

ارث بری template جنگو این مشکلات را حل کرده است. نسخه ی insite-out از include های سمت سرور را بیاد می آورید. به جای تعریف تکه کد های مشترک، تکه کد هایی که تعریف می شوند متفاوت از یکدیگر هستند.

اولین گام برای تعریف یک template پدر، یک اسکلت بندی از صفحه ی شما که template های فرزند بعدا آن را پر خواهند کرد. در مثال زیر یک template پدر تعریف شده است:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>{% block title %}{% endblock %}</title> </head> <body> <h1>My helpful timestamp site</h1> {% block content %}{% endblock %} {% block footer %} <hr> <p>Thanks for visiting my site.</p> {% endblock %} </body> </html>

مثال فوق که base.html نام دارد، یک اسکلت بندی ساده ی HTML می باشد که برای تمام صفحات استفاده خواهد شد. صفحات درون سایت که از صفحه ی فوق ارث بری کرده اند و به عبارتی صفحات فرزند نامیده می شوند می توانند خصوصیات مشخص شده در کلاس پدر را بازنویسی و یا تغییر دهند، می توانند خصوصیاتی را اضافه کنند و حتی می توانند خصوصیتی را نیز حذف کنند و در خودشان از استفاده نکنند. (در صورتیکه با مثال های کتاب پیش میروید فایل فوق را با نام base.html درون دایرکتوری template ذخیره کنید.)

در اینجا از یک تگ template ای که آن را مشاهده کرده اید استفاده می کنید: تگ {% block %}. تمام تگ های {% block %} به موتور template این را می گویند که template فرزند ممکن است این قسمت از template را باز نویسی کند.

اکنون یک template پدر موجود می باشد، می توان از آن در فایل current_datetime.html به شکل زیر استفاده کرد:

{% extends "base.html" %} {% block title %}The current time{% endblock %} {% block content %} <p>It is now {{ current_date }}.</p> {% endblock %}

همچنین فایل hours_ahead را نیز که در آموزش view و urlconf جنگو در مورد آن صحبت شده است را نیز در مثال زیر مشاهده خواهید کرد: (در صورتیکه همگام با مثال های کتاب پیش میروید hours_ahead را از حالت قبلی که به صورت کد مستقیم درون view نوشته شده است خارج کرده و مانند زیر به صورت یکی از template ها درون دایرکتوری template دخیره کنید.)

{% extends "base.html" %} {% block title %}Future time{% endblock %} {% block content %} <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> {% endblock %}

آیا روش فوق روش زیبایی نیست؟ هر template حاوی کدهای منحصر به خود می باشد. هیچ کد زائدی وجود ندارد. در صورتیکه نیاز به تغییر طراحی در یک سایت عظیم دارید، تنها کافیست که درون template پدر تغییر ایجاد کنید، در اینصورت تمام template هایی که از کلاس پدر ارث بری کرده اند نیز به سرعت تغییر خواهند خواهند کرد.

در زیر نحوه ی کار روش فوق توضیح داده شده است. هنگامی که template، current_datetime.html بارگذاری می شود، موتور template به تگ {% extends %} نگاه می کند، که به این اشاره دارد که فایل مورد نظر یک template فرزند می باشد. در اینصورت موتور template به سرعت template پدر را بارگذاری می کند که در این مورد template پدر base.html می باشد.

توجه داشته باشید که template های فرزند بلاک footer را تعریف نکرده اند، template system از مقدار مشخص شده ی بلاک درون template پدر بجای آن استفاده کرده است. مقدار مشخص شده ی درون یک تگ {% block %} در یک template پدر همیشه به صورت یک مقدار یدکی استفاده می شود.

ارث بری تاثیری بر روی context template نخواهد داشت. به عبارت دیگر، هر template فرزند به هر یک از متغیر های template درون context دسترسی خواهد داشت.

می توان به صورت چندین سطح از ارث بری استفاده کرد. یکی از روش های عمومی استفاده از روش ارث بری در سه سطح می باشد:

یک template با نام base.html که بسازید که محتویات اصلی سایت را در بر بگیرد، محتویاتی که به ندرت تغییر خواهند کرد، البته اگر نگوییم هرگز تغییر نخواهند کرد.

یک template با نام base_SECTION.html برای هر بخش از سایت خود ایجاد کنید (مانند base_photos.html و base_forum.html). این template ها باید از base.html ارث بری کنند و باید حاوی طراحی مربوط به خود باشند.

template های هر نوع از صفحه را ایجاد کنید، مانند صفحه ی انجمن (forum) یا یک آلبوم عکس. این template ها از template مناسب مربوط به خود ارث بری کنند.

در زیر دستور العمل های کار با ارث بری template را مشاهده می کنید:

در اغلب موارد، آرگومانی که به {% extends %} ارسال می شود یک رشته خواهد بود، ولی این آرگومان می تواند یک متغیر نیز باشد، در صورتیکه شما نام template پدر را تا زمان اجرا نمی دانید. این خصوصیت اجازه می دهد یک حرکت پویا انجام دهید.