مُقدّمة
تعرّفنا في الدّروس السّابقة على العديد من ميّزات مُحرّك القوالب Jinja وكيفيّة استخدامها لتصميم صفحات HTML بسرعة، إذ بدأنا بمبدأ المرشّحات ثمّ مررنا على الاختبارات لنُنهي مشوارنا عبر التّعرف على طرق لتفادي تكرار شفرة HTML وإعادة استخدام القوالب أو أجزاء منها في مشروع مُعيّن، بل يُمكنك كذلك كتابة شيفرة واحدة واستعمالها مع أكثر من مشروع لما يُوفّره لنا مُحرّك القوالب Jinja من مرونة في التّطوير وقابليّة إعادة استعمال الشّفرة في مُختلف الظّروف. في هذا الدّرس، سنتعرّف على السّياق (Context) في Jinja عند التّضمين والاستيراد لتتفادى الوقوع في أخطاء يصعب تصحيحها.
لتطبيق أمثلة هذا الدّرس، يُمكنك إنشاء تطبيق Flask صغير ليقوم بتقديم قوالب HTML أو يُمكنك استعمال إطار عمل آخر مثل Pyramid أو Django أو Bottle لكن سيتوجّب عليك البحث عن كيفيّة استعمال Jinja مع إطار العمل الذي تختاره.
السّياق في مُحرّك القوالب Jinja عند تضمين قالب في قالب آخر أو عند الاستيراد
يعني مُختلف المُتغيّرات والدّوال المُعرّفة في جزء مُعيّن من الشّفرة. فمثلا، إن عرّفت مُتغيّرا في الجزء العلوي من قالب HTML كما يلي:
{% set website = 'academy.hsoub.com' %}
بعد تعريف المُتغيّر website
في القالب، فسيُصبح هذا المُتغيّر مُتاحا في هذا القالب فقط، ما يعني بأنّك لن تستطيع الوصول إلى المُتغيّر website
في قالب HTML آخر دون استيراده.
السّياق عند تضمين قالب داخل قالب آخر
فلنضع السّيناريو التّاليَ لتتوضّح الفكرة أكثر، لنقل بأنّ لدينا ملفّات HTML التّالية:
- base.html
- index.html
- url.html
مُحتويات ملفّ base.html
ستكون كالتّالي:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
وملفّ index.html
يرث من الملفّ base.html
مع تعريف المُتغيّر website
وتضمين الملفّ url.html
باستعمال الجملة include
:
{% extends 'base.html' %}
{% block title %} My Application {% endblock %}
{% block body %}
{% set website = 'academy.hsoub.com' %}
{% include 'url.html' %}
{% endblock %}
لنقل بأنّك تُريد الوصول إلى قيمة المُتغيّر website
داخل الملفّ url.html
لعرض الرّابط داخل وسم <a>
كما يلي:
{# 'url.html' #}
<a href='http://{{ website }}'>{{ website }}</a>
ستكون النّتيجة كما يلي:
<a href='http://academy.hsoub.com'>academy.hsoub.com</a>
نجح الأمر لأنّ السّياق قد مُرِّر من الملفّ index.html
إلى الملفّ url.html
عند استخدام التعليمة include
، ما يعني بأنّ المُتغيّرات المُعرّفة في الملفّ الأصلي ستكون مُتاحة في الملفّ الفرعي الّذي ضُمِّن بالجملة include
.
لكنّك لن تستطيع الوصول إلّا إلى المُتغيّرات التي عُرّفت قبل استعمال الجملة include
.
ما يعني بأنّك لو عرّفت المُتغيّر website
بعد تضمين القالب url.html
كما يلي:
{% include 'url.html' %}
{% set website = 'academy.hsoub.com' %}
فالقالب url.html
لن يتعرّف على المُتغيّر website
وسيعتبره سلسلة نصيّة فارغة لأنّه لا يستطيع الوصول إلى قيمته.
ستحصل بالتّالي على النّتيجة التّالية:
<a href='http://'></a>
لاحظ بأنّ مُحرّك القوالب Jinja لم يُصدر أية أخطاء، لذا كن حذرا من هذا النّوع من المشاكل الصّامتة، وتأكّد دائما من الاطّلاع على مصدر الصّفحة لتفهم ما يحدث وتستطيع حلّ المُشكلة.
تضمين قالب داخل قالب آخر باستعمال التعليمة include
يُمرّر السّياق مبدئيا من قالب لآخر ، لكن إن أردت منع حدوث هذا الأمر، يُمكنك استعمال التّعبير without context
لمنع القالب الفرعي من الوصول إلى سيّاق القالب الأصلي، وبالتّالي لن يتمكّن من الوصول إلى المُتغيّرات التّي سبق تعريفها.
لتجربة هذا، أضف التّعبير without context
إلى صفحة index.html
ليُصبح مُحتوى الملفّ كما يلي:
{% extends 'base.html' %}
{% block title %} My Application {% endblock %}
{% block body %}
{% set website = 'academy.hsoub.com' %}
{% include 'url.html' without context %}
{% endblock %}
إن ألقيت نظرة على النّتيجة، ستجدها مُشابهة لما كانت عليه عندما عرّفنا المُتغيّر website
بعد التعليمة include
ما يعني أنّ القالب url.html
لم يعد مُؤهّلا للوصول إلى قيمة المُتغيّر، ولهذا نفس التّأثير مع جميع المُتغيّرات والدّوال المُعرّفة في السّياق.
السّياق عند الاستيراد
يُمرّر السّياق مبدئيا بين القوالب عند استعمال الجملة include
، لكنّ العكس يحدث عند استيراد قالب داخل قالب آخر.
لتوضيح هذه الفكرة، لنُغيّر مُحتويات الملفّ url.html
إلى الماكرو التّالي :
{% macro url() %}
<a href='http://{{ website }}'>{{ website }}</a>
{% endmacro %}
لاحظ بأنّ الماكرو لا يقبل أية مُعاملات، لكنّنا نحاول أن نصل إلى المُتغيّر website
داخل الماكرو.
لنُغيّر الآن التعليمة include
إلى جملة import
لاستيراد هذا الماكرو من القالب url.hmtl
:
{% set website = 'academy.hsoub.com' %}
{% from 'url.html' import url %}
{{ url() }}
لاحظ بأنّنا نقوم بالاستيراد بعد تعريف المُتغيّر.
بما أنّ السّياق لا يُمرّر مبدئيا عند الاستيراد، فالنّتيجة ستكون كما لو أنّ قيمة المُتغيّر website
فارغة.
استعمل التّعبير with context
عند الاستيراد كما يلي، للتصريح برغبتك في تمرير السّياق :
{% from 'url.html' import url with context %}
التّعبير with context
له تأثير مُعاكس لتأثير التّعبير without context
، لذا فالمُتغيّر website
سيُمرَّرُ إلى القالب url.html
وبالتّالي فالماكرو url()
يستطيع الوصول إلى قيمة المُتغيّر ومن ثمّ عرضه بصيغة رابط.
ملحوظة: المثال أعلاه مُجرّد توضيح لفكرة السّياق عند الاستيراد، ومن الأفضل استعمال المُعاملات لنقل قيمة مُتغيّر إلى ماكرو مُعيّن عوضا عن تفعيل السّياق.
الخلاصة أنّك تستطيع التّحكم في كيفيّة تعامل القوالب مع السّياق عند التضمين أو الاستيراد عبر استخدام كلّ من التّعبيرين with context
و without context
.
الحالة المبدئية للتعليمة include
هي كالتّالي:
{% include 'url.html' with context %}
والحالة االمبدئية للتعليمة import
:
{% import 'url.html' as url without context %}
تجاهل تضمين القوالب إن لم تكن متواجدة أساسا
سأعرض لك في هذه الفقرة بشكل وجيز تقنيتين من التّقنيات التّي ستُساعدك على تصميم قوالب HTML أفضل عند استخدام التعليمة include
.
أولا، يُمكنك منح مُحرّك القوالب Jinja إمكانيّة تضمين قالب فقط إن كان موجودا عبر تمرير قائمة من أسماء القوالب إلى التعليمة include
كالتّالي:
{% include ['page1.html', 'page2.html'] %}
إذا كان القالب page1.html
موجودا فسيكون للمثال أعلاه نفس تأثير ما يلي:
{% include 'page1.html' %}
سواء أكان القالب page2.html
موجودا أم لا فهذا غير مُهمّ ما دام القالب page1.html
أول قالب في القائمة وكان موجودا بالفعل داخل مُجلّد templates
.
أمّا في حالة لم يكن القالب page1.html
موجودا داخل مُجلّد القوالب وكان القالب page2.html
موجودا عوضا عنه، فهذا الأخير هو القالب الذي سيُضمّن.
وفي حالة لم يكن أي قالب من القوالب المُوفَّرة موجودا، فستحصل على خطأ كالتّالي:
jinja2.exceptions.TemplatesNotFound
TemplatesNotFound: none of the templates given were found: page1.html, page2.html
ولتجاهل هذا الخطأ وعرض مُحتويات القالب index.html
رغم عدم وجود هذه القوالب المُضمَّنة، يُمكنك إضافة التّعبير ignore missing
عند استعمال التعليمة include
كالآتي:
{% include ['page1.html', 'page2.html'] ignore missing %}
التّعبير ignore missing
ليس محصورا بقائمة قوالب فقط، بل تستطيع كذلك استخدامه عند تضمين قالب واحد فقط كما يلي:
{% include "sidebar.html" ignore missing %}
عند استعمال التّعبير، سيتحقّق مُحرّك القوالب Jinja من أنّ القالب sidebar.html
موجود في مُجلّد القوالب، إن كان كذلك فعمليّة التّضمين ستكون ناجحة دون أخطاء، وإن لم يكن القالب موجودا فلن تحدث أية أخطاء وسيبقى مكان التعليمة include
فارغا عند عرض النّتيجة.
تنبيه:
عند استخدام التّعبير ignore missing
مع كلّ من التّعبيرين with context
و without context
في آن واحد، تأكّد من أنّ التّعبير ignore missing
يأتي أولا.
ما يعني بأنّ الأمثلة أسفله صحيحة:
{% include ['page1.html', 'page2.html'] ignore missing with context %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}
والأمثلة التّاليّة خاطئة:
{% include ['page1.html', 'page2.html'] with context ignore missing %}
{% include "sidebar.html" with context ignore missing %}
{% include "sidebar.html" without context ignore missing %}
خاتمة
تعرّفنا في هذا الدّرس على كيفيّة عمل السّياق في Jinja عند التّضمين والاستيراد، بعد قراءتك لهذا الدّرس، يجب أن تكون قادرا على إدارة السّياق باحترافيّة وتتجنّب المشاكل التي تقع في حالة إساءة فهم كيفيّة عمل السّياق، في الدّرس التّالي، سنتعرّف على تقنيات متقدّمة للتّعامل مع حلقات for
من أجل تحسين تطبيقاتك وتكتب شفرة أكثر فعاليّة عند تطوير تطبيقات الويب باستعمال إطار العمل Flask أو أي إطار عمل يعتمد على Jinja.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.