مُقدّمة
تعرّفنا في الدّروس السّابقة على كيفيّة الاستفادة من مُحرّك القوالب Jinja أثناء تطوير تطبيقات ويب باستخدام إطار العمل Flask ، خاصّة ميّزتي الماكرو والمُرشّحات، اللّتان تُعتبران من أهمّ ميّزات Jinja، وبعد أن ألقينا نظرة على أهم المُرشّحات المبنيّة مُسبقا، يُمكن ألّا تجد ما يسدّ حاجتك في هذه المُرشّحات وقرّرت أنّك تملك أفكارا أخرى يُمكن أن تحوّلها إلى مُرشّح لمُساعدتك على تفادي تكرار الشّيفرة والتطوير بشكل أسرع، إن كان الأمر كذلك، فهذا الدّرس هو كل ما تحتاج إليه لتعلّم كيفيّة إنشاء مُرشّحات أخرى وكيفيّة استعمالها مع إطار العمل Flask، إذ سنستخدم مشروع “كلمة” الذي نحن بصدد بنائه كمثال على كيفيّة إنشاء واستخدام مُرشّحاتك الخاصّة.
إنشاء مُرشّحات خاصّة بك
بعد أن تعرّفنا على كيفيّة استعمال المُرشّحات المبنيّة مُسبقا في Jinja، سننتقل إلى جزء آخر مهمّ لتطوير تطبيقات الويب باستعمال إطار العمل Flask ومُحرّك القوالب Jinja، وهو كيفيّة إنشاء مُرشّحات خاصّة بك.
لكن قبل أن ننتقل إلى كيفيّة إنشاء مُرشّح جديد، يجب أن تُدرك بأنّ هناك أكثر من طريقة لإنشاء مُرشّح مع إطار العمل Flask ولأنّ طريقة إنشاء مُرشّح يُشبه إلى حد ما طريقة إنشاء مُوجّه ما، فمكان إنشاء المُرشّح مُهمّ، إذ يُحدّد المكان الذي تُنشئ فيه المُرشّح القوالبَ التّي تستطيع الوصول إلى هذا المُرشّح، وهذا لأنّ سياق التّطبيق يكون مُختلفا بين المُخطّطات blueprints والكائن app
الرّئيسيّ إذ أنّ هذا الأخير يُعتبر عامًا (أي أنّ جميع القوالب تستطيع الوصول إلى المُرشّح) وعند استخدام مُخطّط لإنشاء مُرشّح، فالقوالب التّي ستتمكّن من الوصول إلى المُرشّح هي فقط القوالب المُرتبطة بالمُخطّطات ولن تتمكّن من استخدام المُرشّح في القوالب الأخرى.
بمعنى آخر، إن أنشأت مُرشّحا في المُخطّط الخاصّة بالمُستخدمين فلن تستطيع استخدامه سوى على قوالب HTML المتواجدة بمُجلّد templates
في المسار project/users
. والمُرشّحات التّي تُنشأ في المخطّط الخاصّ بالمقالات لن تستطيع استخدامها سوى مع القوالب الخاصّة بالمقالات، أمّا إن أردت إنشاء مُرشّحات للوصول إليها بشكل عام في كل التّطبيق بحيث تتمكّن جميع قوالب HTML من الوصول إلى المُرشّح واستخدامه فسيتوجّب عليك إنشاؤه باستعمال الكائن app
الذي يتواجد في ملفّ __init__.py
داخل مُجلّد المشروع project
أي المسار project/__init__.py
.
بما أنّنا نستعمل الملفّ filters.html
كحقل تجارب، وبما أنّه لا ينتمي إلى مُخطّط مُعيّن، فسنقوم بإنشاء المُرشّحات في هذه الفقرة باستخدام الكائن app
، لكن إن رأيت في تطبيقاتك بأنّ مُرشّحا ما خاص بمُخطّط مُعيّن ولا حاجة لمُشاركته مع قوالب HTML الأخرى، فلك الحريّة في إنشائه تحت مُخطط وليس باستعمال الكائن app
.
كيف يعمل المُرشّح
فكرة المُرشّح بسيطة، إذ يأخذ قيمة ما كمُعامل ويُرجع قيمة أخرى، والتّالي نموذج يُبيّن طريقة إنشاء مُرشّح خاصّ بك:
@app.template_filter('filter_name')
def filter_name_function(value):
return value
المُرشّح أعلاه شبيه جدّا بمُوجّه عادي، بحيث نستخدم مُزخرفا template_filter
ونُعطيه اسما ما بين القوسين، والدّالة المُزَخرَفةُ تأخذ قيمة value
ومن ثمّ تُرجع نفس القيمة أمّا اسم الدّالة فهو غير مُهمّ، ما يعني بأنّك تستطيع تسميّة الدّالة بأي اسم تُريده إلّا أنّه من المُفضّل أن يصف تأثير المُرشّح، فمثلا، مُرشّح لعرض الاسم الأول لمُستخدم يجب أن تُسمّى دالّته بالاسم first_name_filter
الشّيء الذي يصف الدّالة والمُرشّح والهدف بشكل واضح ومفهوم لمن يقرأ شيفرة التّطبيق.
لاستخدام المُرشّح سيتوجّب عليك استخدام اسمه الذي خصّصته ما بين قوسين (أي الاسم filter_name
في المثال أعلاه)، كما يلي:
{{ value | filter_name() }}
إن جرّبت المثال فستُلاحظ بأنّ القيمة value
لا تتغيّر، وهذا لأنّ ما يُرجعه المُرشّح هو نفسه القيمة التّي يأخذها.
لتفهم أهميّة السّطر return
، جرّب تغييره إلى ما يلي:
@app.template_filter('filter_name')
def filter_name_function(value):
return 'Hello World!'
الآن، المُرشّح لا يقوم سوى بمُهمّة واحدة، بحيث يقوم بتحويل أيّ قيمة يستقبلها إلى القيمة Hello World!
ما يعني أنّك إذا استخدمته في أي مكان في قالب HTML فستتحوّل القيمة إلى Hello World!
.
سنتطرّق لاحقا إلى أمثلة أكثر واقعيّة، لكن عليك أن تفهم بأنّ القيمة التّي تُرجعها الدّالّة المسؤولة عن المُرشّح هي القيمة النّهائيّة التّي ستظهر على المُتصفّح لذا فلتحويل القيمة التي تستقبلها سيتوجّب عليك القيام بكل شيء داخل الدّالة قبل إرجاع أي شيء بالجملة return
.
أمثلة على إنشاء مُرشّحات وكيفيّة استعمالها
بالمثال يتّضح المقال، ولأنّ مُرشّحات Jinja تُستخدم بطرق مُختلفة وكثيرة، مثال واحد لا يكفي، إذ يُمكن للمُرشّح أن يكون بسيطا كما يُمكن أن يكون مُعقّدا، لذا ففي الأمثلة التّاليّة سننتقل من أمثلة بسيطة إلى أمثلة أكثر تعقيدا، وستُساعدك هذه الأمثلة على فهم كيفيّة إنشاء مُرشّح، طريقة استخدامه والأهم من ذلك، ستكتسب فكرة عن الحالات التّي سيتوجّب عليك التّوقف فيها عن تطوير تطبيقك وكتابة مُرشّح لمُساعدتك على تنفيذ مُهمّة بشكل أسرع، بل تستطيع حتى أن تحفظ المُرشّحات التّي تكتبها لاستعمالها في أكثر من تطبيق، فمثلا إن أنشأت مُرشّحا لترجمة كلمات شائعة في تطبيقك (المثال الأول)، فقد تستفيد منه في تطوير تطبيق آخر يتطلّب إنجاز المُهمّة ذاتها، وإن نشرته على منصّة مثل منصّة Github فقد يستفيد منه أشخاص أكثر.
كيفيّة إنشاء مُرشّح Jinja خاص بك، المثال الأول: مُرشّح ترجمة الكلمات
في هذا المثال الأول، سنقوم بإنشاء مُرشّح لترجمة كلمات من اللغة الانجليزيّة إلى اللغة العربيّة، وسيعتمد هذا المثال على قاموس Python بسيط يحتوي على بضعة كلمات ومُقابلاتها في اللغة العربيّة.
سيكون المُرشّح كالتّالي:
@app.template_filter('translate')
def translate_filter(value):
english_to_arabic = {'Hello': u'مرحبا',
'Flask': u'فلاسك',
'Python': u'بايثون',
'Javascript': u'جافاسكربت',
'Academy': u'أكاديميّة'
}
arabic_word = english_to_arabic[value]
return arabic_word
ستُلاحظ أولا بأنّنا سمّينا المُرشّح بالاسم translate
وهذا هو الاسم الذي سنستعمله إذا ما أردنا تطبيق المُرشّح في قوالب HTML، أمّا الدّالة فاسمها translate_filter
وكما قلت سابقا، فاسم الدّالة لا يهم، لكن من المُفضّل أن يشرح الاسم هدف الدّالة. بعدها أنشأنا القاموس english_to_arabic
ليحتوي على بضعة كلمات إنجليزيّة ونظيراتها باللغة العربيّة كمثال بسيط، وبالطّبع، ففي مثال واقعي، سيتوجّب عليك الحصول على الكلمات وترجماتها من قاعدة بيانات وليس من قاموس عادي. في السّطر ما قبل الأخير، نُعرّف المُتغيّر arabic_word
لتحمل الكلمة العربيّة التي نحصل عليها من القاموس باستعمال القيمة value
التّي تُمرّر إلى المُرشّح كمفتاح. أمّا في السّطر الأخير فإنّنا نقوم بإرجاع مُحتوى المُتغيّر arabic_word
.
المثال التّالي يوضّح كيفيّة استعمال المُرشّح الذي أنشأناه للتّو:
{{ 'Python' | translate }}
النّتيجة ستكون الكلمة "بايثون” لأنّها الكلمة التي تُعتبر قيمة للمفتاح Python
في القاموس english_to_arabic
.
المثال التّالي يشمل جميع الكلمات المُتواجدة في القاموس الصّغير الذي أنشأناه:
{% set words = ['Flask', 'Python', 'Hello', 'Javascript', 'Academy'] %}
{% for word in words %}
<p> {{ word }}: {{ word | translate }} </p>
{% endfor %}
النّتيجة:
Flask: فلاسك
Python: بايثون
Hello: مرحبا
Javascript: جافاسكربت
Academy: أكاديميّة
كيفيّة إنشاء مُرشّح Jinja خاص بك، المثال الثّاني
في هذا المثال، سنقوم بإنشاء مُرشّح للحصول على إجمالي الأحرف في قائمة ما، ما يعني بأنّنا سنجمع العناصر النّصيّة في القائمة لتكون على شكل سلسلة نصيّة واحدة، بعدها سنحسب عدد الأحرف في السّلسلة النّصيّة النّاتجة، ومنه نُرجع النّاتج ليُعرض في المُتصفّح.
إليك شيفرة المُرشّح:
@app.template_filter('list_len')
def list_length_filter(value):
joined_list = "".join(value)
length = len(joined_list)
return length
إن تمعّنت في الشّيفرة فستفهمها لأنّ الفكرة وراءها سهلة، أولا، نقوم بضم جميع القيم في مجموعة العناصر value
ونُخزّن النّتيجة داخل المُتغيّر joined_list
، بعدها نحسب عدد أحرف النّتيجة المُتواجدة داخل المُتغيّر joined_list
عبر استخدام الدّالة len
التّي تقوم بحساب عدد عناصر سلسلة معيّنة في لغة بايثون، وفي الأخير نُرجع النّتيجة length
التّي تُمثّل عدد عناصر السّلسلة joined_list
، وهكذا فإنّ النّتيجة ستكون دائما عددا موجبا على شرط أن تكون القيمة value
عبارة عن مجموعة من العناصر.
المثال التّالي يُوضّح كيفيّة المُرشّح list_len
الذي أنشأناه مع قائمة باسم numbers
:
{% set numbers = ['One', 'Two', 'Three'] %}
{{ numbers | list_len }}
النّتيجة ستكون العدد 11 وهو عدد أحرف الكلمات One
، Two
و Three
مُجتمعة.
مثال آخر:
{% set words = ['Flask', 'Python', 'Hello', 'Javascript', 'Academy'] %}
{{ words | list_len }}
النّتيجة:
33
مُلاحظة: هذا المثال مُجرّد توضيح لكيفيّة إنشاء مُرشّح Jinja خاص بك وإن أردت تطبيق الفكرة في هذا المثال فيُمكنك الوصول إلى نفس النّتيجة عبر استعمال كل من المُرشّح join
والمُرشّح length
دون الحاجة إلى كتابة مُرشّح خاص بك.
المثال التّالي يُوضّح كيفيّة الحصول على نفس النّتيجة باستعمال كل من join
و length
:
{{ words | join("") | length }}
كيفيّة إنشاء مُرشّح Jinja خاص بك، المثال الثّالث
في هذا المثال، سنقوم بإنشاء مُرشّح لعرض صورة على المُتصفّح مُباشرة من رابطها، هذا يعني بأنّنا لن نحتاج إلى تمرير الرّابط كقيمة إلى الخاصيّة src
في الوسم <img />
.
يجب أن نكون قادرين على استعمال المُرشّح كما يلي:
image_link | image() | safe()
سيتوجّب علينا استخدام المُرشّح safe
لأنّ نتيجة المُرشّح image
ستكون عبارة عن شيفرة HTML، ولتمكين المُتصفّح من ترجمة هذه الشّيفرة، لا بد من استخدام المُرشّح safe
.
** مُلاحظة: ** استخدام المُرشّح safe
خطير كما تعلم، لذا فيجب عليك أن تتأكّد من أنّ رابط الصّورة سليم وآمن قبل استخدام المُرشّح image
عليه، من طرق التّأكد من أنّ الرّابط سليم هو تفادي منح المُستخدمين إمكانيّة إضافة روابط للصوّر، فإن أدخل مُستخدم ما شيفرة HTML وشيفرة Javascript عوضا عن رابط صورة فقد يتعرّض تطبيقك لهجمة خبيثة قد تُمكّن المُهاجم من الوصول إلى قاعدة بيانات التّطبيق أو سرقة حسابات مُستخدميك، لذا تأكّد من أنّ رابط الصّورة آمن قبل استعمال المُرشّح safe
.
في هذا المثال، يُمكن أن يكون المُرشّح بسيطا بحيث يعرض الصّورة المُتواجدة في الرّابط بأبعادها الأصليّة وبطريقة عاديّة، لكن يُمكننا أن نعمل على جعل المُرشّح أحسن باستعمال المُعاملات للتّحكم بكيفيّة عرض الصّورة، وللمزيد من المرونة، سنُضيف إمكانيّة التّحكم في حجم الصّورة عبر تمرير الحجم المرغوب إلى مُعامل باسم width
أثناء تطبيق المُرشّح.
لذا إن أردنا أن تكون الصّورة بحجم 200 px فسيتوجّب أن نكون قادرين على استخدام المُرشّح كما يلي:
image_link | image(width=200) | safe
بالإضافة إلى التّحكم بحجم الصّورة، سنُضيف كذلك إمكانيّة التّحكم بقيمة خاصيّة border-radius
في لغة CSS لتحديد مدى استدارة حواف الصّورة.
مع هذه الإضافة، المثال التّالي سيُنتج صورة بحجم 100 px وقيمة 5 px للخاصيّة border-radius
أي أنّها ستكون مُستديرة الحواف قليلا:
image_link | image(width=200, radius=5)
بعد أن تعرّفنا على فكرة المُرشّح، لننتقل الآن إلى إنشائه.
الشّيفرة التّالية تُمثّل شيفرة المُرشّح image
مع إمكانيّة تحديد حجم الصّورة المعروضة وتحديد مدى استدارة حوافها:
@app.template_filter('image')
def image_filter(value, width=500, radius=0):
css_style = "'width: {}px; border-radius: {}px'".format(width, radius)
html_code = '''
<img src={} style={} />
'''.format(value, css_style)
return html_code
هناك العديد من الأمور التّي قد لا تُفهم في هذا المُرشّح، لذا لا بد من شرح مُفصّل.
أولا، نقوم بإنشاء مُرشّح باسم image
، الدّالة المسؤولة تأخذ ثلاثة مُعاملات، القيمة الأولى تُعطى للمُعامل الأول، وهي عبارة عن القيمة التّي يأخذها المُرشّح أثناء استدعائه (أي ما يسبق الرّمز |
) والتّي ستكون رابط أو مسار الصّورة المرغوب عرضها، المُعامل width
عبارة عن المُعامل الذي يُحدّد حجم الصّورة، إذا لم يتوفّر حجم مُحدّد أثناء استدعاء المُرشّح فالحجم الافتراضي هو 500. بالنّسبة للمُعامل radius
فسيكون المُعامل الذي يُحدّد مدى استدارة حواف الصّورة، والقيمة الافتراضية هي 0 أي أنّ الصورة ستظهر بشكل عادي دون استدارة للحواف إذا لم تتوفّر قيمة أكبر من 0 للمُعامل radius
أثناء استخدام المُرشّح على رابط الصّورة لعرضها.
نُعرّف المُتغيّر css_style
داخل الدّالة ليحمل شيفرة لغة CSS لتعديل الصّورة حسب قيم كل من الحجم و مدى استدارة الحواف التّي نحصل عليها من المُتغيّرين width
و radius
. ستُلاحظ بأنّنا نستخدم التّابع format
لدمج قيم المُتغيّرين داخل السّلسلة النّصيّة، بهذه الطّريقة ستكون القيمة الافتراضيّة للمُتغيّر css_style
ما يلي:
'width: 500px; border-radius: 0px'
في السّطر التّالي، نُعرّف المُتغيّر html_code
نقوم باستخدام خاصيّة تعدّد الأسطر في لغة بايثون عبر إحاطة شيفرة HTML بثلاثة علامات تنصيص ما يسمح لنا بتوزيع قيمة المُتغيّر على أكثر من سطر.
في شيفرة HTML، نقوم باستخدام الوسم <img>
لعرض الصورة عبر تمرير رابط أو مسار الصّورة إلى الخاصيّة src
، كما نقوم بتمرير شيفرة CSS التّي تتواجد داخل المُتغيّر css_style
إلى الخاصيّة style
لتنسيق الصّورة حسب الحجم ومدى استدارة الحواف بلغة CSS.
في الأخير نقوم بإرجاع شيفرة HTML المُتواجدة داخل المُتغيّر html_code
والتّي ستكون مسؤولة عن عرض الصّورة.
اختبار مُرشّح عرض الصّور
بعد الانتهاء من إنشاء المُرشّح image
لعرض الصّور، يُمكنك اختباره كما يلي:
image_link | image(width=100) | safe
مع التّأكد من أنّ المُتغيّر image_link
عبارة عن رابط مُباشر للصورة.
يُمكنك مثلا تجربة المُرشّح مع صورة رمزيّة لأحد دروس إطار العمل Flask السّابقة عبر تجربة السّطر التّالي:
'https://academy.hsoub.com/uploads/monthly_2016_05/flask-introduction.png.b896f4a662940d3b348b5b95f5eac86a.png' | image(width=100) | safe
بعد تجربة المثال أعلاه، ستُلاحظ صورة درس "مدخل إلى تطوير تطبيقات الويب باستخدام إطار العمل Flask” بحجم 100px، ويُمكنك تغيير الحجم أو مدى استدارة الحواف كما تشاء.
التّالي مثال على كيفيّة عرض نفس الصّورة بحجم أكبر وحواف أكثر استدارة:
<center>
<h1> إنشاء مُرشّحات Jinja خاصّة بك </h1>
<br>
{{ 'https://academy.hsoub.com/uploads/monthly_2016_05/flask-introduction.png.b896f4a662940d3b348b5b95f5eac86a.png' | image(width=300, radius=20) | safe }}
</center>
نتيجة المثال أعلاه ستكون مُشابهة لما يلي:
خاتمة
تعرّفنا في هذا الدّرس والدّروس السّابقة على كيفيّة استخدام مُرشّحات Jinja وكيفيّة إنشاء مُرشّحات خاصّة بك، لذا ستتمكّن الآن من استعمال ما تعلّمته لتطوير تطبيقات أكثر تعقيدا لتُلبي احتياجاتك وتُطبّق أفكارك بسهولة وطرق أحسن من ذي قبل. في الدّرس المُقبل، سنُنهي سلسلة الدّروس المُخصّصة لمُحرّك القوالب Jinja عبر التّعرف على مبدأ الاختبارات ومن ثمّ ننتقل إلى إكمال تطوير تطبيق "كلمة” في بقيّة الدّروس.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.