در این بخش ما موضوعات زیر را بررسی خواهیم کرد:
- ویژگیهای زبان تمپلیت جنگو
- جینجا ۲ (Jinja2)
- سازماندهی تمپلیتها
- چگونه تمپلیتها کار میکنند
- بوتسترپ (Bootstrap)
- الگوی درختی وراثت در تمپلیت
- الگوی لینک فعال
وقت آن است که از سومین تفنگدار در سهگانه MTV صحبت کنیم؛ تمپلیتها. تیم شما ممکن است دیزاینری داشته باشد که مسؤول طراحی تمپلیتها باشد یا ممکن است خود شما آنها را طراحی کنید. در هر حالت لازم است که یا تمپلیتها کاملاً آشنا باشید. در نهایت تمپلیتها هستند که با کاربر واقعی روبرو میشوند.
جنگو زبانهای تمپلیتی زیادی را پشتیبانی میکند. در اینجا ما ابتدا به زبان تمپلیت خود جنگو نگاهی میاندازیم که به صورت پیشفرض در هر پروژه، وجود دارد.
بیایید ابتدا نگاهی سریع به ویژگیهای DTL یا Django Template Language داشته باشیم.
متغیرها
هر تمپلیت یک مجموعه از متغیرهای زمینه (context) را دریافت میکند. مانند متد format() در رشتههای پایتونی که با یک آکولاد {variable}، مشخص میشود، جنگو از دو آکولاد {{ variable }} استفاده میکند. ببینیم چطور با هم تفاوت دارند:
در پایتون روش نوشتن <h1>{title}</h1>
است. برای مثال:
>>> "<h1>{title}</h1>".format(title="SuperBook") '<h1>SuperBook</h1>'
همین عبارت در تمپلیت جنگو به صورت <h1>{{ title }}</h1>
نوشته میشود. رندر کردن این عبارت با متغیر زمینه قبلی نتیجه یکسانی خواهد داشت:
>>> from django.template import Template, Context
>>> Template("<h1>{{ title }}</h1>").render(Context({"title": "SuperBook"}))
'<h1>SuperBook</h1>'
صفات یا Attributes
نقطه، یک اپراتور چند منظوره در تمپلیتهای جنگو است. سه نوع عملیات مختلف وجود دارد: جستجوی صفت، جستجوی دیکشنری و یا جستجوی ایندکس لیست (به همین ترتیب).
ابتدا متغیرهای زمینه و کلاسها را مشخص کنیم. در پایتون:
>>> class DrOct:
arms = 4
def speak(self):
return "You have a train to catch."
>>> mydict = {"key":"value"}
>>> mylist = [10, 20, 30]
حالا بیایید به دستور زبان پایتون برای این سه نوع جستجو نگاه کنیم:
>>> "Dr. Oct has {0} arms and says: {1}".format(DrOct().arms,
DrOct().speak())
'Dr. Oct has 4 arms and says: You have a train to catch.'
>>> mydict["key"]
'value'
>>> mylist[1]
20
معادل آن در تمپلیت جنگو به این صورت خواهد بود:
Dr. Oct has {{ s.arms }} arms and says: {{ s.speak }} {{ mydict.key }}
{{ mylist.1 }}
نگاه کنید که متد speak، که هیچ ارگومانی به غیر از self نمیگیرد، در اینجا مانند یک صفت با آن رفتار شده است.
فیلترها
بعض مواقع لازم است که متغیرها تغییر کنند. ممکن است بخواهید فانکشنهای مختلفی را روی یک متغیر اعمال کنید. به جای صدا کردن فانکشنها به صورت زنجیروار پشت سر هم مانند var.method1().method2(arg)، جنگو از روش پایپ کردن استفاده میکند {{ var|method1|method2:"arg" }}، که شبیه به فیلترهای یونیکس است. با اینحال این روش فقط برای فیلترهای پیشفرض یا فیلترهای تعریف شده به صورت اختصاصی، کار میکند.
یک محدودیت دیگر این است که فیلترها نمیتوانند به متن تمپلیت دسترسی داشته باشند. این فیلترها فقط به کمک دیتا و آرگومانهایی که به آنها ارسال میشود کار میکنند. بنابراین در درجه اول، برای تغییر متغیرها در متن تمپلیت به کار میروند.
این دستور را در پایتون اجرا کنید:
**>>> title="SuperBook"**
**>>> title.upper()[:5]**
**'SUPER'**
در ادامه، معادل آن را در تمپلیت جنگو میبینید:
{{ title|upper|slice:':5' }}
تگها
زبانهای برنامه نویسی، کاری بیش از نشان دادن متغیرها میتوانند انجام دهند. زبان تمپلیت جنگو فرمهای نوشتاری آشنای زیادی مانند for دارد. این دستورها باید در روش نوشتاری تگها مانند {% if %}
نوشته شوند. بسیاری از فرمهای اختصاصی تمپلیت مانند include و block نیز باید به همین صورت نوشته شوند.
در شل پایتون:
>>> if 1==1:
... print(" Date is {0} ".format(time.strftime("%d-%m-%Y")))
Date is 30-05-2018
در ادامه، همین عبارت را در شکل تمپلیت جنگو میبینید:
{% if 1 == 1 %} Date is {% now 'd-m-Y' %} {% endif %}
فلسفه - یک زبان برنامهنویسی اختراع نکنید
یک سوال رایج بین تازهکارها این است که چطور محاسبات عددی مانند پیدا کردن درصدها را در تمپلیت انجام دهیم. بر اساس فلسفه طراحی، سیستم تمپلیت عمداً اجازه انجام این موارد را نمیدهد:
- نسبت دادن مقدار به متغیرها
- صدا زدن فانکشنها به همراه آرگومان
- بهکارگیری منطقهای پیشرفته
این تصمیم گرفته شده تا اجازه ندهد منطقهای کسب و کار را در تمپلیت قراردهید. بر اساس تجربه من با PHP یا زبانهای مشابه ASP، ترکیب منطق با سیستم ارائه، میتواند یک کابوس جدی برای نگهداری کد باشد. با اینحال شما میتوانید تگهای اختصاصی را (که به زودی به آن میپردازیم) برای انجام هر نوع محاسبهای، مخصوصاً اگر مربوط به ارائه باشد، بنویسید.
بهترین روش
منطق کار را از تمپلیت دور نگه دارید.
فارغ از این توصیه، برخی ممکن است موتور تمپلیت کمی قویتری را ترجیح بدهند. در اینصورت Jinja2 احتمالاً همان چیزی است که نیاز دارید.
جینجا ۲ از نظر نگارش بسیار شبیه به DTL است. اما در بعضی موارد، فلسفه کمی متفاوتی دارد. برای مثال، در DTL صداکردن متدها مانند مثالهای زیر است:
{% for post in user.public\_posts %}
...
{% endfor %}
اما در جینجا ۲، ما فراخوانی متد public_posts را مانند فراخوانی تابع پایتونی انجام میدهیم:
{% for post in user.public\_posts() %}
...
{% endfor %}
این به آن معنی است که در جینجا ۲ بر خلاف DTL میتوانید توابع را با آرگومان فراخوانی کنید. برای دیدن چنین تفاوتهای ظریفی به مستندات Jinja2 مراجعه کنید.
جینجا ۲ معمولاً به دلایل زیر انتخاب میشود:
- آشنایی: ممکن است طراح شما از قبل با جینجا ۲ آشنا باشد.
- کنترل فضای خالی: جینجا ۲ کنترل بهتری روی فضاهای خالی بعد از رندر شدن تگها دارد.
- قابلیت سفارشی سازی: تمام جنبههای جینجا ۲ از تعریف مارکاپ برای رشتهها تا تعریف اکستنشنها به سادگی قابل انجام است.
- عملکرد: بعضی بررسیها نشان میدهد که جینجا ۲ از جنگو سریعتر است.
- قابلیت Autoescape: به صورت پیشفرض جینجا ۲ برای عملکرد بهتر، قابلیت Autoescape را در XML/HTML غیرفعال میکند.
در اکثر موارد، این مزایا فقط برای استفاده از جینجا ۲ نیست، بلکه میتواند دلیل خوبی برای استفاده از سایر موتورهای تمپلیت مانند Mako و Genshi باشد.
آشنایی با DTL منحنی یادگیری را برای هر فرد جدیدی که به پروژه شما وارد شود، کاهش میدهد. علاوه بر این DTL، هم خوب به کارگرفته شده و هم خوب تست شده است. در نهایت ممکن است لازم باشد تگهای تمپلیت جنگو مانند url یا static را در موتور تمپلیت جدید به همان شکل تمپلیت جنگو، تکرار کنید.
تا زمانی که دلیل خوبی برای تغییر زبان تمپلیت ندارید، پیشنهاد میکنم که با همان زبان تمپلیت جنگو پیش بروید. در ادامه این بخش ما از DTL استفاده میکنیم.
ترکیببندی اولیه پروژه که به کمک دستور startproject انجام میشود، محلی برای تمپلیتهای شما تعریف نمیکند. اما این کار بسیار راحتی است.
یک دایرکتوری به نام templates در پوشه اصلی پروژه بسازید. مقدار DIRS را در متغیرهای TEMPLATES در فایل settings.py تعیین کنید (فایل تنظیمات در آدرس superbook/settings/base.py در پروژه سوپربوک قابل دیدن است):
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
همین، حالا برای مثال میتوانید یک تمپلیت به نام about.html بسازید و مانند زیر، از طریق فایل urls.py به آن ارجاع دهید:
urlpatterns = [
path('about/', TemplateView.as_view(template_name='about.html'), name='about'),
اگر مقدار APP_DIRS برابر با True باشد، تمپلیتهای شما میتوانند درون پوشه اپ شما قرار داشته باشند. ساخت یک دایرکتوری جداگانه برای تمپلیتها روش ایدهآلی برای نگهداری تمپلیتهای هر اپ است.
در اینجا چند روش ارائه شده که روشهای خوبی برای سازماندهی تمپلیتهاست:
- تمپلیتهای هر اپ را در دایرکتوری تمپلیتها و در یک دایرکتوری جدا نگه دارید. مثلاً projroot/app/templates/app/template.html، توجه داشته باشید که app دوبار در آدرس دیده میشود.
- از پسوند .html برای تمپلیتها استفاده کنید.
- برای تمپلیتهایی که تکه کدهایی هستند که درون سایر تمپلیتها استفاده میشوند از پیشوند _ استفاده کنید، مانند _navbar.html
ترتیب معرفی دایرکتوریهای تمپلیت اهمیت زیادی دارد. برای فهم بهتر آن، نیاز است که بدانید جنگو چطور تمپلیتها را رندر میکند.
همانطور که نمودار زیر نشان میدهد، جنگو تمپلیتها را بدون آگاهی از موتور واقعی تمپلیت، رندر میکند:
تصویرسازی ساده از رندر تمپلیت در جنگو
هر تمپلیت به ترتیب با بکاند تمپلیتهایی که در متغیرهای TEMPLATES در فایل settings.py تعریف شده است، امتحان میشود.
یک شئ Loader مربوط به بکاند تمام تمپلیتها را جستجو خواهد کرد. بر اساس تنظیمات بکاند، لودکنندههای مختلفی استفاده میشوند. برای مثال filesystem.Loader، تمپلیتهای فایل سیستم را بر اساس DIRS، لود میکند و app_directories.Loader تمپلیتهای درون پوشه اپها را لود میکند.
اگر یک Loader موفق باشد، جستجو قطع میشود و همان موتور بکاند تمپلیت، برای رندر کردن انتخاب میشود. نتیجه این کار یک شئ Template خواهد بود که شامل تمپلیت تجزیه شده و کامپایل شده است.
بر ای رندر کردن Template باید آن را با یک شئ Context آماده کنید. Context دقیقاً مانند یک دیکشنری عمل میکند، اما مانند دستهای از دیکشنریها ساخته شده است. اگر یک Template شامل تعدادی متغیر باشد، Context مقادیری است که به این متغیرها نسبت داده میشود.
هنگامی که از Context های جنگو استفاده میکنید میبایست با RequestContext بیشتر آشنا شوید که زیرکلاسی از Context است. یک RequestContext با اجرای پردازشگر زمینه تمپلیت، زمینههای (context) بیشتری را به تمپلیت اضافه میکند. جینجا ۲ به پردازشگر زمینه نیاز ندارد چرا که از فراخوانی فانکشن به طور مستقیم، پشتیبانی میکند.
در نهایت، روش رندر کردن Template، یک زمینه را دریافت میکند و خروجی را رندر میکند. خروجی میتواند HTML، ایمیل ، CSS، XML یا هر خروجی متنی باشد.
اگر شما ترتیب جستجو کردن تمپلیتها را متوجه شوید، میتوانید با توجه به اهداف خود، تمپلیتهای لود شده را بازنویسی کنید. در زیر چند سناریو وجود دارد که میتواند مفید باشد:
- بازنویسی یک تمپلیت از اپ شخص ثالث با تمپلیتهای تعریف شده در پروژه خودتان
- از جینجا ۲ برای بخشهایی که عملکرد در آنها مطرح است استفاده کنید و برای سایر بخشها از DTL استفاده کنید
حالت اول به حاطر استفاده از فریمورکهایی مانند بوتسترپ، وضعیت رایجی است.
مادام O
برای اولین بار بعد از چند هفته، دفتر استیو در گوشه سالن پر از جنب و جوش بود. با استخدامهای جدید، تیم پنج نفره متشکل از برَد، اِوان، جیکوب، سو و استیو است. مانند یک تیم ابرقهرمانی، تواناییهای آنها به طرز شگفتانگیزی متعادل است.
برد و اوان، کدنویسی میکنند. در حالی که اوان روی جزییات متمرکز است برد مسول کنترل دورنمای کارهاست. جیکوب با توانایی بررسی گوشه و کنارها، فرد مناسبی برای تست کردن است. سو مسؤولیت بازاریابی و طراحی را بر عهده دارد.
در واقع، کل طراحی قرار بود توسط یک آژانس طراحی آوانگارد انجام شود. نزدیک دو ماه طول کشید تا یک طرح اولیه پر رنگ و لعاب که مورد علاقه مدیریت بود آماده شود. دو هفته دیگر هم طول کشید تا یک ماکت HTML از طراحی فوتوشاپی تهیه شود. با اینحال همانطور که انتظار میرفت به خاطر کند و دست و پاگیر بودن در موبایلها، این طراحی کنار گذاشته شد.
استیو از شکست طرحی، که الان به طور گسترده طرح استفراغ تک شاخ نامیده میشد، ناامید شده بود. هارت با او تماس گرفته بود و از عدم پیشرفت پروژه برای گزارش دادن به مدیریت، نگران بود.
هارت با لحنی تلخ به استیو یادآوری کرد «ما زمانهای ذخیره پروژه را مصرف کردهایم. دیگر نمیتوانیم منتظر شگفتیهای لحظه آخر باشیم».
همین موقع بود که سو، که به طرز غیر منتظرهای ساکت بود گفت به کمک بوتسترپ توییتر، روی یک ماکت پروژه کار میکرده است. سو یک هکر توسعه بود، یک کدنویس مشتاق و بازاریابی خلاق.
او اعتراف کرد که فقط مهارتهای ابتدایی HTML را دارد. با اینحال ماکت او به طرز شگفتانگیزی کامل و برای کاربران سایر شبکههای اجتماعی معاصر، آشنا به نظر میرسید. از همه مهمتر، طراحی او ریسپانسیو بود و روی هر دستگاه موبایل یا تبلت به درستی کار میکرد.
همه مدیران به غیر از شخصی به نام مادام O، به اتفاق با طرح سو موافقت کردند. یک روز جمعه بعد از ظهر، او به سرعت کنار میز سو آمد و در مورد همه چیز شروع به سؤال کردن کرد. از رنگ پسزمینه تا سایز کرسر موس. سو سعی کرد با متانت و آرامش قابل توجهی همه چیز را توضیح دهد.
یک ساعت بعد، وقتی استیو تصمیم گرفت که مداخله کند، مادام O داشت میپرسید که چرا تصویر پروفایل باید در یک دایره باشد به جای آنکه مربع باشد. استیو جواب داد «چنین تغییر گستردهای در سراسر سایت به هیچ وجه در زمان مورد نظر تمام نمیشود». مادام O نگاهش را به سمت او برد و لبخند حیلهگرانهای زد. ناگهان استیو موجی از شادی و امید را حس کرد. به شدت احساس آرامش میکرد و هیجانزده بود. صدای خودش را شنید که با خوشحالی با تمام درخواستهای مادام O موافقت میکند.
بعدها استیو یادگرفت که مادام Optimism یک ذهنگرای کوچک است که میتواند بر ذهنهای مستعد تاثیر بگذارد. تیم او دوست داشت که در هر موقعیتی این موضوع را پیش بکشد.
اینروزها به ندرت کسی تمام یک وبسایت را از ابتدا طراحی میکند. فریمورکهای CSS مانند Twitter's Bootstrap یا Zurb's Foundation با امکاناتی مانند سیستم گرید، تایپوگرافی عالی و استایلهای از قبل آماده شده، نقطه شروع آسانی هستند. اکثر آنها از طراحی وب ریسپانسیو استفاده میکنند که باعث میشود سایت شما برای موبایلها مناسب باشد.
یک وبسایت که از بوتسترپ ورژن 3.3 تغییریافته و با استفاده از اسکلتبندی پروژه Edge طراحی شده است
ما از بوتسترپ استفاده خواهیم کرد اما روش کار برای سایر فریمورکهای CSS هم شبیه به همین است. سه راه مختلف برای بهکارگیری بوتسترپ در پروژه وجود دارد:
- ** یک اسکلتبندی پروژه پیدا کنید**: اگر هنوز پروژه را شروع نکردهاید پس بهتر است یک اسکلتبندی پروژه که بوتسترپ هم داشته باشد پیدا کنید. یک اسکلتبندی پروژه مانند Edge (که واقعاً توسط شما ساخته شده) میتواند به عنوان ساختار اولیه در هنگام ساخت پروژه استفاده شود، مانند زیر:
$ django-admin.py startproject -- template=https://github.com/arocks/edge/archive/master.zip -- extension=py,md,html myproj
همچنین میتوانید از یکی از تمپلیتهای cookiecutter که دارای پشتیبانی بوتسترپ هستند استفاده کنید.
- استفاده از پکیج: اگر پروژه خود را شروع کردهاید، آسانترین گزینه استفاده از یک پکیج مانند django-bootstrap4 است.
- کپی کردن دستی: هیچکدام از گزینههای قبلی تضمین نمیکند که نسخه بوتسترپ آنها، آخرین نسخه منتشر شده باشد. نسخههای بوتسترپ چنان با سرعت منتشر میشوند که نویسندگان پکیجها کار بسیار سختی برای بهروز نگهداشتن بوتسترپ مورد استفاده در پکیجها دارند. بنابراین، اگر می خواهید با آخرین نسخه بوتسترپ کار کنید، بهترین گزینه آن است که خودتان آن را از http://getbootstrap.com دانلود کنید. مطمئن شوید که یادداشتهای مربوط به انتشار نسخه را خوانده باشید تا ببینید که آیا نیاز است برای هماهنگی با نسخه جدید، تغییراتی در کد خود بدهید یا نه. پوشه dist را که شامل css، js و پوشه فونتها است، در پوشه static که درون پوشه اصلی پروژه است کپی کنید. مطمئن شوید که مسیر این پوشه در متغیر STATICFILES_DIRS در فایل settings.py تعریف شده باشد:
STATICFILES_DIRS = [os.path.join(BASE\_DIR, "static")]
اکنون میتوانید بخشهای بوتسترپ را به شکل زیر در پروژه خود اضافه کنید:
{% load staticfiles %}
<head>
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
اما همه آنها شبیه هم هستند!
بوتسترپ ممکن است برای شروع سریع، فوقالعاده باشد. با اینحال بعضی مواقع توسعهدهندهها تنبل میشوند و حوصله ندارند که ظاهر پیشفرض آن را تغییر دهند. این کار باعث می شود که سایت تاثیر ضعیفی بر کاربران شما بگذارد و باعث شود آنها ظاهر سایت را زیادی آشنا و غیر جذاب بدانند.
نسخه Bootstrap 4 به همراه ویژگیهایی متشر شده است که جذابیت ظاهری را افزایش داده است. شما میتوانید یک فایل custom.scss بسازید و همه چیز را مانند رنگبندی و نقاط شکست گریدها را شخصیسازی کنید. مستندات این نسخه شرح داده است که چطور میتوانید این فایلها را کامپایل و تبدیل به استایلشیت کنید.
با تشکر از جامعه توسعهدهندگان اطراف بوتسترپ، وبسایتهای بسیار زیادی مانند bootswatch.com وجود دارد که استایلشیتهای آمادهای دارند که فقط کافی است فایل bootstrap.min.css را در پروژه خود جایگزین کنید.
آخرین نکته، شما میتوانید کلاسهای CSS خود را به کمک تغییر دادن نام کلاسهایی مانند row یا col-lg-9 با تگهای معنایی مانند main یا article، با معناتر کنید. این کار را میتوانید با چند خط کد SASS و توسعه دادن کلاسهای بوتسترپ به شکل زیر انجام دهید:
@import "bootstrap";
body > main { @extend .row;`
article { @extend .col-lg-9; } }
این کار به کمک ویژگی به نام میکسین (به نظر آشنا نمیآید؟) امکانپذیر میشود. به کمک فایلهای اصلی SASS، بوتسترپ میتواند به صورت کامل برای نیازهای شما، شخصیسازی شود.
جایگزینهای سبک
مرورگرهای قدیمی در مورد اجرا کردن CSS بسیار غیر یکسان عمل میکردند. آنها نه تنها پیشوندهای مخصوص تأمینکننده مانند -WebKit-transition را داشتند بلکه ویژگیهای مخصوص به خود را هم داشتند. مروگرهای جدیدتر، استانداردهای مدرن را بهتر دنبال میکنند.
حالا ما علاوه بر این صفحهبندیهای قدرتمندی مانند flexbox را داریم که پیچیدگی کد را کمتر میکند. تمام اینها باعث بوجود آمدن فریموکهای سبک CSS شده است.
برای مثال، Pure.css به صورت minify شده و gzip شده ولی باویژگیهای قابل قبول، فقط ۳.۸ کیلوبایت است. مشابه آن mini.css با تمرکز بر دستگاههای موبایل و مرورگرهای مدرن طراحی شده و به صورت gzip، زیر ۷ کیلوبایت است. برای مقایسه بوتسترپ با تمام ماژولها و به صورت gzip شده، ۲۵ کیلوبایت است.
با اینکه این فریمورکهای سبک میتواند سرعت لود شدن اولیه را بهبود بدهند مطمئن باشید که با تمام مرورگرهایی که ممکن است کاربران شما از آن استفاده کنند، اینها را تست کنید. ابزارهایی مانند CanIUse.com میتواند با نشان دادن اینکه کدام ویژگی در کدام مرورگر و پلتفرم پشتیبانی میشود یا نه، کمک خوبی باشد. بوتسترپ، با طیف وسیع مشتریانش، تقریباً در پشتیبانی از نسخههای قدیمیتر خود، خوب است.
زبان تمپلیت جنگو بسیار ساده است. با اینحال شما با پیروی از چند الگوی طراحی زیبا، میتوانید در زمان، به خوبی صرفهجویی کنید. بیایید به تعدادی از آنها نگاهی بکنیم.
** الگو — درخت وراثت تمپلیت**
مشکل: تمپلیت به تعداد زیادی markup در صفحههای مختلف نیاز دارد.
راه حل: هرجا که ممکن است از الگوی وراثت استفاده کنید و تکه کدهای مورد نظر را include کنید.
جزییات مشکل
کاربرها نیاز دارند که صفحات وبسایت از یک الگوی یکسان پیروی کند. برخی عناصر مانند منوی دسترسی، هدر و فوتر در تمام اپلیکیشن ها دیده میشوند و تکرار آنها در هر صفحه، دست و پا گیر خواهد بود.
اکثر زبانهای تمپلیت، یک مکانیزم include دارند. محتوای یک فایل دیگر، معمولاً یک تمپلیت، در محلی درون فایل تمپلیت دیگری فراخوانی میشود و در آنجا اضافه میشود. این موضوع میتواند در یک پروژه بزرگ خسته کننده باشد.
توالی قطعاتی که در یک تمپلیت فراخوانی میشوند معمولاً یکسان است. ترتیب فراخوانی بسیار مهم است و کنترل کردن آن برای یافتن خطاها دشوار است. به صورت ایدهآل، ما باید بتوانیم یک ساختار پایهای درست کنیم. صفحههای جدید باید به این ساختار پایه اضافه شوند و فقط تغییرات یا اضافات را در آن اعمال کنند.
جزییات راه حل
تمپلیتهای جنگو، یک مکانیزم توسعه قوی دارند. شبیه به ساختار کلاسها در زبانهای برنامهنویسی، یک تمپلیت میتواند از طریق وراثت، توسعه داده شود. اما برای اینکه این روش استفاده شود باید فایل پایه دارای ساختار بلوکی مانند زیر باشد.
تمپلیت ماژولار پایه میتواند توسط صفحات دیگر توسعه داده شود و ترکیببندی یکسان و منعطفی را ایجاد کند.
فایل base.html به طور مرسوم، ساختار پایه برای کل سایت است. این تمپلیت معمولاً به صورت یک HTML خوشفرم (یعنی با یک مقدمه و با باز و بسته شدن تگهای HTML) ساختاربندی شده و با چندین placeholder که به صورت تگهای {% block tags %} نمایش داده میشوند پر شده است. برای مثال، یک فایل base.html ساده شبیه به نمونه زیر خواهد بود:
<html>
<body>
<h1>{% block heading %}Untitled{% endblock %}</h1> {% block content %}
{% endblock %}
</body>
</html>
در اینجا دو بلوک داریم؛ heading و content که میتوانند در فایلهای دیگر بازنویسی شوند. شما میتوانید صفحههای خاصی بسازید که این بلوکها را بازنویسی کنند و صفحه پایه را توسعه دهند. برای مثال در اینجا یک صفحه About داریم:
{% extends "base.html" %}
{% block content %}
<p> This is a simple About page </p> {% endblock %}
{% block heading %}About{% endblock %}
مجبور نیستیم ساختار پایه را هر بار تکرار کنیم. همچنین میتوانیم بلوکها را به هر ترتیبی که میخواهیم بنویسیم. نتیجه رندر شده نهایی، هر بلوک را در جای صحیح خود که در فایل base.html مشخص شده، قرار خواهد داد.
اگر ساختار وراثتی تمپلیت، یک بلوک را بازنویسی نکرده باشد، محتوای موجود در والد، استفاده خواهد شد. در مثال قبل اگر بلوک heading بازنویسی نشود، هدینگ موجود در والد که Untitled است، استفاده خواهد شد. شما میتوانید به طور مشخص از محتوای تمپلیت والد، با استفاده از {{ block.super }}، بهره ببرید. این روش برای مواقعی خوب است که میخواهید به محتوای والد چیزی را اضافه کنید.
یک تمپلیت که از الگوی وراثت استفاده میکند میتواند دوباره به ارث برده شود و زنجیره ارثبری را ایجاد کند. این الگو میتواند باعث ایجاد چندین فایل پایه با ترکیببندیهای مختلف شود مثلاً یک الگوی صفحه تک ستونی درست کرد یا یک تمپلیت پایه هم برای section های مختلف مانند صفحه وبلاگ سایت درست کرد.
معمولاً تمامزنجیرهای وراثت، به فایل base.html میرسند برای همین به آن الگوی درخت وراثت تمپلیت گفته میشود. البته لازم نیست همهجا از این الگو استفاده کرد. صفحات خطای 404.html و 500.html معمولاً به ارث نمیرسند و برای جلوگیری از خطاهای بیشتر اکثر تگهای تمپلیت در آنها حذف میشود.
راه دیگر رسیدن به این هدف ممکن است استفاده از پردازشگر زمینه باشد. شما میتوانید یک پردازشگر زمینه درست کنید که یک متغیر زمینه را برای تمام تمپلیتهای شما به صورت عمومی قابل استفاده کند. ولی اینکار برای بخشهایی مانند سایدبار توصیه نمیشود چرا که با خارج کردن ارائه محتوا از لایه تمپلیت، قاعده تفکیک لایهها (جدا بودن منطق برنامه از نمایش محتوا) را نقض میکند.
الگو —لینک فعال
مشکل: منوی دسترسی یک جزء تکراری در اکثر صفحههاست. با اینحال، لینک فعال باید نشان دهد که کاربر در کدام صفحه است.
راه حل: با مشروط کردن لینک فعال به کمک تعریف متغیرهای زمینه یا بر اساس مسیر درخواست شده
جزییات مشکل
راه ساده به کارگیری لینک فعال در منوی دسترسی، تنظیم دستی آن در هر صفحه است که نه ضد اشتباه است و نه بر اساس قوانین DRY (خودت رو تکرار نکن).
جزییات راه حل
راه حلهای زیادی به غیر از روشهای مبتنی بر جاوااسکریپت، وجود دارد که لینک فعال ایجاد کند. این راه حلها میتواند در دو گروه بر مبنای تمپلیت و بر مبنای تگ اختصاصی، تقسیم شوند.
راه حل بر مبنای تمپلیت
با تعریف کردن متغیر active_link هنگام include کردن تکه کد مربوط به منوی دسترسی. این راه حل هم ساده است و هم به راحتی پیادهسازی میشود.
در هر تمپلیت لازم است این تکه کد را اضافه کنید (یا آن را به ارث ببرید):
{% include "_navbar.html" with active_link='link2' %}
فایل _navbar.html شامل یک منوی دسترسی با تعدادی متغیر برای تعریف لینکهای فعال است:
{# \_navbar.html #}
<ul class="nav nav-pills">
` `<li{% if active\_link == "link1" %} class="active"{% endif %}><a href="{% url 'link1' %}">Link 1</a></li>
` `<li{% if active\_link == "link2" %} class="active"{% endif %}><a href="{% url 'link2' %}">Link 2</a></li>
` `<li{% if active\_link == "link3" %} class="active"{% endif %}><a href="{% url 'link3' %}">Link 3</a></li>
</ul>
تگهای اختصاصی
تمپلیتهای جنگو، مجموعه همهکارهای از تگهای داخلی را ارائه میکنند. بسیار ساده است که تگ اختصاصی خود را بنویسید. با توجه به اینکه هر تگ اختصاصی درون یک اپ تعریف میشود یک پوشه templatetags درون اپ بسازید. این پوشه باید یک پکیج باشد در نتیجه باید یک فایل خالی به نام __init__.py داشته باشد. سپس تگ اختصاصی خود را در یک فایل پایتون بنویسید. برای مثال برای این الگوی لینک فعال، ما میتوانیم یک فایل به نام nav.py، با محتویات زیر بسازید:
# app/templatetags/nav.py
from django.core.urlresolvers import resolve from django.template import Library
register = Library()
@register.simple_tag
def active_nav(request, url):
url_name = resolve(request.path).url_name
if url_name == url:
return "active"
return ""
این فایل یک تگ اختصاصی به نام active_nav درست میکند. این فانکشن یک مسیر URL را از آرگومان ریکوئست میگیرد (مثلاً /about/، برای توضیحات بیشتر در مورد مسیرهای URL، بخش ۴: ویوها و URLها را ببینید ). سپس از فانکشن resolve() استفاده میشود تا نام-الگوهای URL (در فایل urls.py) بر اساس آرگومان ورودی جستجو شود. در نهایت، رشته "active" در صورتی بازگردانده میشود که نام-الگو با نام-الگو مورد نظر یکی باشد.
نحوه صدا زدن این تگ اختصاصی در تمپلیت به شکل {% active_nav request 'pattern_name' %} است. توجه داشته باشید که ریکوئست باید به هر صفحهای که از این تگ استفاده شده، ارجاع داده شود.
استفاده از یک تگ در تعداد زیادی صفحه میتواند سنگین باشد. برای همین ما یک پردازشگر زمینه داخلی به نام TEMPLATE_CONTEXT_PROCESSORS در فایل settings.py اضافه میکنیم. در نتیجه ریکوئست، در متغیرهای ریکوئست، در کل سایت قابل دسترس خواهد بود. مانند زیر:
# settings.py
[
'django.core.context_processors.request',
]
حالا تنها کاری که باقی مانده این است که از این تگ اختصاصی در تمپلیتها جهت تعیین لینک فعال استفاده کنید:
{# base.html #}
{% load nav %}
<ul class="nav nav-pills">
<li class={% active\_nav request 'active1' %}><a href="{% url 'active1' %}">Active 1</a></li>
<li class={% active\_nav request 'active2' %}><a href="{% url 'active2' %}">Active 2</a></li>
<li class={% active\_nav request 'active3' %}><a href="{% url 'active3' %}">Active 3</a></li>
</ul>
در این بخش، ما به ویژگیهای تمپلیتهای جنگو نگاه کردیم. هرچند که تغییر دادن ربان تمپلیت جنگو ساده است اما بسیاری از افراد در مورد تغییر دادن آن احتیاط میکنند. با اینحال مهم است که فلسفه طراحی زبان تمپلیت جنگو را قبل از آنکه آن را با نمونههای جایگزین تغییر دهیم، بدانیم.
در بخش بعد به یکی از ویژگیهای بسیار جذاب جنگو، یعنی بخش ادمین و نحوه عملکرد و تغییر آن نگاه میکنیم.