تعرّفنا في الدرس السابق على القسمين الثاني والثالث من بنية المشاريع في إطار العمل Django وهما العروض Views والقوالب Templates، وقد تحدّثنا عن العروض وآلية عملها بشكل مفصّل، وسنتطرّق في هذا الدرس بشيء من التفصيل إلى القوالب وآلية عملها وسنتعرّف كذلك على محرّك القوالب الخاص بـ Django.
ما هي القوالب؟
نظرًا لكون Django إطار عمل للويب فإنّه بحاجة إلى وسيلة لتوليد شيفرات HTML بصورة ديناميكية، ويستخدم Django القوالب لهذا الغرض، إذ يحتوي القالب على أجزاء ثابتة تضم شيفرة HTML وCSS إضافة إلى صيغة برمجية خاصة تتحكم في طريقة إضافة المحتوى الديناميكي إلى القالب تسمى لغة قوالب Django (DTL).
قالب Django عبارة عن ملف نصي يستخدم لغة قوالب Django، ويتضمن هذا الملف بعض الأمور التي يتم تفسيرها من قبل محرك القوالب، وأهمّها المتغيرات واﻷوسمة.
ﻻ بدّ أنّك قد لاحظت أنّه في كلّ مرة أجرينا فيها عملية ربط القالب، فقد قمنا بتعريف سياق المتغيرات Variable Context معه. يقوم Django بتصيير Rendering القالب مع السياق المرتبط به، حيث يتم استبدال أسماء المتغيرات بالقيم المرتبطة بها وذلك بعد مطابقتها مع سياق المتغيرات المرفق مع القالب، ويتم كذلك تنفيذ الوسوم الموجودة في ملف القالب، أما ما تبقى في هذا الملف فيظهر كما هو.
المتغيرات
يعرض المتغير القيمة المرتبطة به عن طريق السياق، وهو قاموس يضم مجموعة من المفاتيح والقيم المرتبطة بها.
لاستخدام المتغيرات في قوالب Django يكفي إحاطتها بقوسين معقوفين بالشكل التالي:
My first name is {{ first_name }}. My last name is {{ last_name }}.
فلو كان سياق المتغيرات بالشكل التالي:
{'first_name: 'Mohammed', 'last_name': 'Taher'}
تكون النتيجة:
My first name is Mohammed. My last name is Taher.
الوسوم
تؤدي الوسوم مهام متعدّدة ومتنوعة، فيمكن للوسم أن يعرض محتوى معين، أو يؤدي وظيفة بنى التحكم كجمل If
الشرطية وحلقات for
التكرارية، أو جلب محتوى من قاعدة البيانات، وغير ذلك الكثير.
تحاط الوسوم في القوالب بقوس معقوف وعلامة النسبة المئوية، كما في المثال التالي:
{% csrf_token %}
ومعظمها يتقبل المعاملات:
{% cycle 'odd' 'even' %}
وتتطلب بعض الوسوم تحديد وسم البداية والنهاية:
{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}
لنلقِ نظرة اﻵن على أشيع الوسوم المستخدمة في لغة قوالب Django:
الجمل الشرطية
يتحقّق الوسم {% if %}
من قيمة المتغير، فإذا كانت القيمة صحيحة (بمعنى أنّ المتغير موجود، وليس فارغًا، ولا يحمل قيمة false
) يتم عرض محتوى المتغير:
{% if article_list %} Number of articles: {{article_list|length}} {% elif article_in_archive %} The Articels are in Archive. {% else %} No articles. {% endif %}
ﻻحظ أنّه يمكن استخدام وسمي {% elif %}
و {% else %}
لمرة واحدة أو لعدة مرات ضمن الوسم If
، وﻻحظ أيضًا أن هذا الوسم يتطلب وجود وسم إغلاق.
يمكن استعمال المعاملات المنطقية (and, or, not)
في الوسم If
، كما يمكن استخدام المعاملات الرياضية (==, !=, <, >, <=, >=, in)
، إضافة إلى إمكانية دمج هذه المعاملات مع بعضها البعض، إليك بعض اﻷمثلة:
{% if athlete_list and coach_list %} Both athletes and coaches are available. {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %} {% if athlete_list and coach_list or cheerleader_list %} There are some athelets and maybe some coaches or cheerleaders. {% endif %} {% if somevar == "x" %} This appears if variable somevar equals the string "x" {% endif %} {% if "bc" in "abcdef" %} This appears since "bc" is a substring of "abcdef" {% endif %} {% if user in users %} If users is a QuerySet, this will appear if user is an instance that belongs to the QuerySet. {% endif %}
حلقة for التكرارية
يؤدي هذا الوسم نفس الوظيفة التي تؤديها أي حلقة for
في أي لغة برمجية، إليك هذا المثال:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
يمكن المرور على عناصر مصفوفة معينة وبصورة عكسية بإضافة كلمة reversed
:
{% for obj in list reversed %}
ويمكن إظهار عناصر قائمة معينة بالشكل التالي:
{% for x, y in points %}
There is a point at {{ x }},{{ y }}
{% endfor %}
ويمكن استخدام هذا الوسم للعرض المفاتيح والقيم المرتبطة بها في قاموس معين:
{% for key, value in data.items %}
{{ key }}: {{ value }}
{% endfor %}
يمكن الوصول إلى عداد الحلقة التكرارية بأساليب مختلفة، وذلك عن طريق مجموعة من المتغيرات يقدّمها محرّك القوالب في Django. فمثلًا forloop.counter
يظهر العدد الحالي للحلقة ويبدأ عدّ الحلقات من الرقم 1، و forloop.counter0
الذي يؤدي نفس الوظيفة ولكن يبدأ العدّ من الرقم 0، و forloop.first
والذي يعطي قيمة True
إن كانت الدورة الحالية هي الدورة اﻷولى ضمن الحلقة، وforloop.last
والذي يؤدي نفس الوظيفة ولكن عند الوصول إلى الدورة اﻷخيرة ضمن الحلقة.
إليك هذا المثال لتوضيح الموضوع:
{% for photo in gallery %}
{% if forloop.counter == 1 %}
Do something with {{ photo }}.
{% endif %}
{% endfor %}
تبدأ حلقة for
بالمرور على عناصر مجموعة معرض الصور gallery
ويتحقق وسم if
أثناء ذلك من العدد الحالي للحلقة، فإن كانت الحلقة هي اﻷولى يتم تنفيذ الشرط، وإلا فلا.
الشيفرة السابقة مطابقة للشيفرة التالية:
{% for photo in gallery %}
{% if forloop.first %}
Do something with {{ photo }}.
{% endif %}
{% endfor %}
تقدّم لغة قوالب Django عددًا كبيرًا من الأوسمة التي تؤدي وظائف متعددة ومتنوعة، ويمكنك الاطلاع على جميع الوسوم المتوفرة ووظائفها من هنا.
المرشحات Filters
تعمل المرشّحات على إجراء تحويل معيّن على قيم المتغيرات والأوسمة، وتستخدم بالشكل التالي:
{{ hsoub|title }}
{% if messages|length >= 100 %}
You hove lots of messages.
{% endif %}
يعمل المرشح title
على تحويل الحرف اﻷول من كل كلمة في قيمة المتغير إلى حرف كبير، فلو كان السياق معرفًا بالشكل التالي:
{'hsoub': 'on a mission to develop the arab world'}
فإن الحرف اﻷول من كل كلمة في العبارة السابقة سيتحول إلى حرف كبير:
On A Mission To Develop The Arab World
يمكن لبعض المرشحات أن تتقبل المعاملات:
{{ my_date|date:"Y-m-d" }}
يقدم محرّك قوالب Django عددًا كبيرًا من المرشحات التي تؤدي وظائف مختلفة، كتنسيق الوقت والتاريخ، وعرض الجمل المناسبة لصيغتي المفرد والجمع، وتكبير اﻷحرف اﻹنكليزية وتصغيرها، وحساب عدد الكلمات وغيرها الكثير. يمكنك الاطلاع جميع المرشحات المتوفرة ووظائفها من هنا.
استخدام محرّك القوالب في تطبيق الاقتراعات
لنعد اﻵن إلى تطبيق الاقتراعات الذي نعمل على إنشائه ضمن هذه السلسلة، ولنتوجه إلى ملف templates/polls/index.html
الذي يحتوي الشيفرة التالية:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>الاقتراعات غير متوفرة حالياً.</p>
{% endif %}
ﻻحظ أنّنا نستخدم في هذا الملف عددًا من المتغيرات واﻷوسمة، إذ يبدأ الملف بوسم If
يتحقق من قيمة المتغير latest_question_list
الموجود في سياق المتغيرات المرفق مع القالب، فإن كانت نتيجة التحقق صحيحة، يضاف وسم <ul>
إلى الملف ثم تبدأ حلقة for
بالعمل، حيث تمرّ على جميع عناصر القائمة latest_question_list
وإسناد كل قيمة إلى المتغير question
. ﻻحظ أن هذا المتغير يضمّ متغيرات فرعية (إن صح التعبير) تحمل قيمًا مختلفة، مثل question.id
و question.question_text
. تقوم بالحلقة بسرد عناصر القائمة مع إضافة وسمي <li>
و <a>
إلى كل عنصر، وبعد الانتهاء يضاف الوسم </ul>
. استخدمنا الوسم else
لعرض رسالة تخبر المستخدم بعدم وجود أي اقتراعات في الوقت الحاضر في حال كانت نتيجة التحقق خاطئة.
توجّه اﻵن إلى الملف detail.html وعدّله ليصبح بالشكل التالي:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
ستعمل الشيفرة السابقة على عرض اﻷجوبة المرتبطة بالسؤال الذي اختاره المستخدم على هيئة قائمة نقطية.
توليد الروابط بصورة ديناميكية
هناك مشكلة صغيرة في قالب index.html
وهي أننا قمنا بكتابة مسار الرابط بأنفسنا، ولم يتم توليد هذا المسار ديناميكيًا، اﻷمر الذي يجعل من تبديل المسار في وقت لاحق أمرًا صعبًا خصوصًا إن تضمن القالب مسارات عديدة.
يمكن لـ Django أن يتكفل بعملية توليد مسارات الروابط بشكل كامل، وذلك باستخدام الوسم {% url %}
ليصبح الملف index.html بالشكل التالي:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>الاقتراعات غير متوفرة حالياً.</p>
{% endif %}
ولكن كيف يتعرّف Django على المسار المطلوب؟ يستخدم Django قيمة المعامل name
الذي قمنا بتعريفه في الدرس الرابع من هذه السلسلة (المسارات في Django). توجّه إلى ملف polls/urls.py
والق نظرة على المسار الخاص بعرض detail:
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail')
ﻻحظ أن هذا المسار يحمل اسمًا خاصًّا به، وقد عرّفناه من خلاله المعامل name
. بهذه الطريقة يتعرّف Django على المسار المطلوب استخدامه في القوالب.
واﻵن إن كنت ترغب في تغيير المسار المرتبط بهذا العرض إلى مسار آخر، وليكن polls/specifics/12/
على سبيل المثال، فيمكن تعديله ضمن ملف polls/urls.py
بدلًا من تعديل المسار في القالب أو القوالب التي تم استخدامه فيها:
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
استخدام نطاقات اﻷسماء للتمييز بين المسارات
يتضمن مشروعنا هذا تطبيقًا واحدًا فقط وهو تطبيق الاقتراعات، ولكن المشاريع الحقيقية تتضمن عددًا كبيرًا من التطبيقات، فكيف يمكن لـ Django إذًا أن يميز بين أسماء المسارات في هذه الحالة؟ على سبيل المثال، يحتوي تطبيق الاقتراعات على عرض باسم detail، وقد يحتوي المشروع على تطبيق مدونة يتضمن عرضًا باسم detail أيضًا، فكيف يمكن لـ Django أن يتعرف على المسار المطلوب عند استخدام الوسم url
في ملف القالب؟
اﻹجابة هي نطاقات اﻷسماء Namespaces. توجه إلى الملف polls/urls.py
وأضف اسم التطبيق في بداية قائمة أنماط المسارات، ليصبح الملف بالصورة التالية:
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
واﻵن عدّل العبارة التالية في القالب polls/index.html
:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
لتصبح بالشكل التالي:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
ختامًا
لا زالت هناك بعض اﻷمور اﻷساسية التي تنقص تطبيق الاقتراعات، فصفحات التطبيق غير منسّقة، كما أنّه لا يوفّر للمستخدم طريقة واضحة للتصويت على الاقتراعات.
في الدرس القادم سنتعرّف على كيفية التعامل مع النماذج Forms بصورة مبسطة لتهيئة آلية التصويت على الاقتراعات، وسنتعرف كذلك على العروض العامة Generic views وسنرى كيف يمكن لهذه العروض أن تختصر الوقت والجهد. بعد ذلك سنقوم بإضافة التنسيقات الخاصة بتطبيق الاقتراعات بواسطة CSS وسنتعرف على مفهوم الملفات الساكنة Static Files في Django.
المصدر:
توثيقات Django
تم التعديل في بواسطة محمد طاهر الموسوي
أفضل التعليقات
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.