مُقدّمة
تعرّفنا سابقا على حلقة التّكرار for
للدّوران على عناصر قائمة أو مفاتيح وقيم قاموس بايثون، سنتعرّف الآن على تقنيات مُتقدّمة ستُساعدك على التّعامل مع حلقة for
على نحو أفضل لتتمكّن من تصميم قوالب HTML مع مُحرّك القوالب Jinja بطريقة أسرع وأكثر إتقانا.
استعمال حلقة for مع قائمة بايثون
تُستعمل حلقة for
مع قوائم بايثون عاديّة كما يلي:
{% set names = ['Ahmed', 'Khalid', 'Ali', 'Abdelhadi', 'Yasser'] %} <ul> {% for name in names %} <li>{{ name }}</li> {% endfor %} </ul>
النّتيجة:
Ahmed
Khalid
Ali
Abdelhadi
Yasser
بهذه الطّريقة، يُمكنك عرض كل عنصر من القائمة داخل وسم HTML مُعيّن وتطبيق تنسيق باستخدام CSS كما تشاء.
استعمال حلقة for مع قواميس بايثون
بالإضافة إلى استعمالها مع قائمة عاديّة، يُمكنك كذلك استعمال حلقة for مع قاموس ما للوصول إلى مفاتيحه وقيّم كلّ مفتاح بحيث تدور حول القاموس لتحصل على كل مفتاح وقيمته، يُمكنك القيام بذلك ببساطة كالتّالي:
{% set website = { 'url': 'academy.hsoub.com',
'company': 'Hsoub',
'description': 'Learn new skills for free'
}
%}
<ul>
{% for key, value in website.iteritems() %}
<li> {{ key }} : {{ value }} </li>
{% endfor %}
</ul>
لاحظ بأنّنا نقوم بالوصول إلى محتويات القاموس عبر تطبيق التّابع iteritems()
على المُتغيّر website
، بحيث نحصل على المفتاح والقيمة عبر المُتغيّرين key
و value
على التّوالي، داخل حلقة for
نقوم بعرض كلّ من المفتاح وقيمته داخل وسم <li>
.
النّتيجة:
url : academy.hsoub.com
company : Hsoub
description : Learn new skills for free
يُمكنك كذلك استخدام تنسيقات إطار العمل Bootstrap لعرض مُحتويات قاموس ما بشكل جميل.
بالإضافة إلى ما سبق، يُمكنك كذلك إسناد قائمة بايثون على هيئة قيمة لمفتاح مُعيّن من القاموس، على سبيل المثال، يُمكن لمقال ما أن يحمل عنوانا واحدا وأكثر من تعليق واحد، بحيث تكون التّعليقات عناصر من قائمة بايثون كما يلي:
{% set post = {'title': 'Introduction to Flask',
'comments': ['Great!', 'Thank you!']
}
مثال تطبيقي
لنجمع الآن الأفكار السّابقة ولنُصمّم صفحة HTML بسيطة لعرض معلومات شخص ما:
{% set person = { 'first_name': 'Ali',
'last_name': 'Sayed',
'age': '27',
'languages': ['Arabic', 'English'],
'Children': ['Hassan', 'Fatima'],
}
%}
<div class="col-sm-4">
<ul class="list-group">
<li class="list-group-item active">
{{ person['first_name']}} {{ person['last_name']}}
</li>
{% for key, value in person.iteritems() %}
{% if value is string %}
<li class="list-group-item">{{ key }} : {{ value }}</li>
{% else %}
<li class="list-group-item">
{{ key }} : {% for item in value %} {{ item }}, {% endfor %}
{% endif %}
</li>
{% endfor %}
</ul>
</div>
رغم أنّ الشّفرة مُعقّدة بعض الشّيء، إلّا أنّها في الحقيقة بسيطة، وستبدو لك كذلك إن تابعت الفقرتين السّابقتين من هذا الدّرس.
إليك ما يحدث في الشّفرة أعلاه، أولا نُعرّف قاموسا باسم person
ليحمل المفاتيح التّالية:
- الاسم الأول للشّخص،
- الاسم العائلي (النّسب)،
- العمر،
- اللغات التي يُتقنها الشّخص،
- أطفاله.
لاحظ بأنّ قيم اللغات والأطفال عبارة عن قوائم بايثون.
في شفرة HTML نقوم بالدّوران حول مُحتويات القاموس person
، بعدها نستعمل الاختبار string
المُعرّف قياسيا في Jinja للتّحقق ممّا إذا كانت القيمة عبارة عن سلسلة نصيّة أو لا، إن كانت كذلك فإنّنا نعرضها مع مفتاحها بشكل طبيعي، إن لم تكن القيمة سلسلة نصيّة فهذا يعني بأنّها قائمة من عناصر مُتعدّدة وأنّ الجزء الذي يلي الكلمة المفتاحيّة else
هو الذي سيُعرَض.
في الجزء else
نقوم بعرض المفتاح ثمّ نستعمل الحلقة for
مُجدّدا للدّوران على عناصر القائمة المُتواجدة في قيمة المفتاح المذكور آنفا.
هذا هو الجزء الخاص بعرض عناصر قائمة بعد قيمة المفتاح:
{% else %}
<li class="list-group-item">
{{ key }} : {% for item in value %} {{ item }}, {% endfor %}
إن استخدمت إطار العمل Bootstrap فستكون النّتيجة مُشابهة لما في الصّورة التّاليّة:
لاحظ بأنّ القاموس غير مُرتّب على نحو صحيح، ذلك لأنّ قواميس بايثون ليست مُرتّبة مبدئيًّا، لكن يُمكنك ترتيب مُحتويات القاموس أبجديا عبر استعمال المُرشّح dictsort
كما يلي:
{% for key, value in person | dictsort %}
مع مُلاحظة أنّك لن تحتاج إلى التّابع iteritems()
عند استعمال المُرشّح.
المُتغيّر loop عند استخدام الحلقة for
حلقة for
تعمل بطريقة بسيطة، إذ تأخذ عدّة قيم وتمنحك كل قيمة داخل مُتغيّر مؤقّت، وفي كلّ دورة تتغيّر قيمة المُتغيّر.
يوفّر مُحرّك القوالب Jinja عند التّعامل مع حلقة for
مُتغيّرا خاصّا داخل الحلقة باسم loop
؛ باستعمال هذا المُتغيّر الخاص، يُمكنك الوصول إلى معلومات خاصّة بالدورة الحاليّة وتُمكّننا كذلك من استعمال تقنيّات الاستدعاء الذّاتي (Recursion) لتضمين عناصر قائمة داخل عناصر قائمة أخرى خاصّة بالدّورة الحاليّة (ستتضّح الصّورة أكثر عندما ننتقل إلى الأمثلة التّطبيقية).
الوصول إلى رقم الدّورة الحاليّة
يُمكنك استخدام الخاصيّة index
مع المُتغيّر loop
في الحلقة for
كما يلي:
{% for item in items %}
{{ loop.index }}
{% endfor %}
مثال:
{% set list = ['Python', 'Flask', 'Jinja',
'Programming', 'Web developement'] %}
{% for item in list %}
<p>{{ loop.index }} - {{ item }}</p>
{% endfor %}
النّتيجة:
1 - Python
2 - Flask
3 - Jinja
4 - Programming
5 - Web development
لاحظ بأنّ العدّ يبدأ من واحد، إن أردت أن يبدأ العدّ من الصّفر، سيتوجّب عليك استخدام التّابع index0
عوضا عن التّابع index
كما يلي:
{{ loop.index0 }}
بهذا التّعديل ستكون النّتيجة كما يلي:
0 - Python
1 - Flask
2 - Jinja
3 - Programming
4 - Web developement
الوصول إلى رقم الدّورة الحاليّة عكسيّا
يُمكنك كذلك عكس تأثير التّابع index
عبر استعمال التّابع revindex
كالتّالي:
{{ loop.revindex }}
النّتيجة:
5 - Python
4 - Flask
3 - Jinja
2 - Programming
1 - Web developement
وللانتهاء بالرّقم 0 يُمكنك استعمال التّابع revindex0
.
التحقّق مما إذا كانت الدّورة الحاليّة هي الأولى أو الأخيرة
يُمكنك استعمال التّابع first
الذي يُرجع القيمة True
إذا كانت الدّورة الحاليّة هي أول دورة في حلقة for
.
وبنفس الطّريقة فإنّ التّابع last
يُساعد على التّحقّق ممّا إذا كانت الدّورة الحاليّة هي الأخيرة أو لا.
مثال:
{% for item in list %}
{% if loop.first %}
<p>{{ loop.index }} (First) - {{ item }}</p>
{% elif loop.last %}
<p>{{ loop.index }} (Last) - {{ item }}</p>
{% else %}
<p>{{ loop.index }} - {{ item }}</p>
{% endif %}
{% endfor %}
النّتيجة:
1 (First) - Python
2 - Flask
3 - Jinja
4 - Programming
5 (Last) - Web developement
الوصول إلى عدد عناصر القيم الإجمالي
بالإضافة إلى إمكانيّة الحصول على عدد عناصر قائمة ما باستعمال المُرشّح count
أو المُرشّح length
، يُمكنك كذلك استخدام loop.length
للحصول على عدد عناصر القيم التي اِستُخْدِمَتْ مع حلقة for
الحاليّة.
يُمكنك التّحقق من الأمر عبر المثال التّالي (على افتراض أنّك تستعمل القائمة list
السّابقة):
<p>{{ list | length }}</p>
<p>{{ list | count }}</p>
{% for item in list %}
<p>{{ loop.length }} - {{ item }}</p>
{% endfor %}
ستُلاحظ بأنّ النّتيجة هي نفسها سواء استخدمنا المرشّحات أو التّابع loop.length
، بهذه الطّريقة يُمكنك الحصول على عدد عناصر قائمة من داخل حلقة for
.
إعادة استعمال نفس الحلقة مع قائمة داخل قائمة أخرى
لنفترض بأنّنا نُريد عرض أسماء أشخاص مع أبنائهم بحيث تكون قائمة HTML الخاصّة بالأبناء تابعة للأب.
إليك البيانات التّي سنستعملها في مثالنا هذا:
{% set people = [ dict(name='Ali', children=[dict(name='Mohammed'), dict(name='Hassan')]),
dict(name='Khaled', children=None),
dict(name='Fahd', children=[dict(name='Kamal'), dict(name='Omar')])
]
%}
في القائمة أعلاه، لدينا ثلاثة قواميس، القاموس الأول خاصّ بعلي، وأطفاله (الذين يعتبرون قائمة من القواميس كذلك) محمد وحسن، أما القاموس الثّاني فخاص بخالد الذي ليس لديه أبناء، والقاموس الأخير خاص بفهد، وأبناؤه كمال وعمر.
لعرض أسماء الآباء الذين يتواجدون في القواميس الثّلاثة، يُمكن أن نستخدم حلقة for
بسيطة، لكن سيتوجّب علينا تكرار الشّفرة إذا ما أردنا الدوران حول أبناء كل شخص.
عوضا عن استخدام أكثر من حلقة for
واحدة، يُمكننا استخدام حلقة for
خاصّة تُكرّر نفسها، ويُمكننا فعل هذا الأمر عبر إضافة الكلمة recursive
عند استخدام حلقة for
كالتّالي:
{% for person in people recursive %}
هكذا سنتمكّن من استعمال المُتغيّر loop
لإعادة الدّوران حول قائمة أطفال كل شخص، لكن سنفعل ذلك فقط إن كان للشّخص أبناء بالفعل، لذا سنتحقّق من أنّ القيمة لا تُساوي القيمة None
عبر الاختبار كما يلي:
{% if person.children is not none %}
<ul class="list-group"> {{ loop(person.children) }} </ul>
{% endif %}
المثال النّهائيّ سيكون كالتّالي:
{% set people = [ dict(name='Ali', children=[dict(name='Mohammed'), dict(name='Hassan')]),
dict(name='Khaled', children=None),
dict(name='Fahd', children=[dict(name='Kamal'), dict(name='Omar')])
]
%}
<div class="col-sm-4">
<ul class="list-group">
{% for person in people recursive %}
<li class="list-group-item"> {{ person.name }}
{% if person.children is not none %}
<ul class="list-group"> {{ loop(person.children) }} </ul>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
النّتيجة ستكون كما في الصّورة التّاليّة:
يُمكنك كذلك معرفة عمق الحلقة باستخدام التّابع loop.depth
داخل حلقة for
من النّوع recursive
كالتّالي:
<span class="badge">{{ loop.depth }} </span>
تأكّد فقط من أن تضع السّطر السّابق مُباشرة بعد السّطر:
{% for person in people recursive %}
النّتيجة ستكون كالتّالي:
لاحظ بأنّ رقم العمق يبدأ من واحد، إن أردت أن يبدأ من الصّفر فاستعمل loop.depth0
.
يُمكنك كذلك استخدام هذه الميّزة مع تعليقات في مُدوّنة أو منصّة تتطلّب تفاعل الأعضاء بين بعضهم البعض.
الصّورة التّاليّة توضيح بسيط للنّتيجة النّهائيّة التي يُمكنك أن تصل إليها إن كنت تمتلك تعليقات متداخلة في قاعدة بياناتك:
خاتمة
تعرّفنا في هذا الدّرس على كيفيّة استخدام حلقة for
في مُحرّك القوالب Jinja للحصول على قوالب HTML أحسن وتطويرها بسرعة. وبهذا نكون قد أكملنا أساسيّات دروس مُحرّك القوالب Jinja وسننتقل في الدّروس القادمة للتّعرف على جزء آخر مُهمّ في تطوير الويب، ألا وهو كيفيّة التّعامل مع قواعد البيانات في التّطبيقات المكتوبة بإطار العمل Flask.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.