إنشاء مرشحات Jinja خاصة بك لاستخدامها في تطبيقات Flask
تُعتبر مرشحات Jinja من الأدوات المهمة التي تساهم بشكل كبير في تحسين تجربة تطوير تطبيقات الويب باستخدام إطار العمل Flask. عند بناء تطبيقات ويب ديناميكية، غالبًا ما تحتاج إلى معالجة البيانات أو تعديلها بطريقة معينة قبل عرضها على المستخدمين، وهنا يأتي دور مرشحات Jinja التي تُتيح لك التحكم الكامل في كيفية عرض البيانات داخل القوالب. في هذا المقال، سنستعرض بشكل موسع ومفصل مفهوم مرشحات Jinja، كيفية إنشاء مرشحات خاصة بك، تطبيقها داخل تطبيقات Flask، وأفضل الممارسات التي تساعد على الاستفادة المثلى منها، مع شرح تقني وعلمي متكامل.
مقدمة عن Jinja ومرشحات القوالب
Jinja هو نظام قوالب (Template Engine) تم تطويره بلغة بايثون، ويُستخدم بشكل واسع مع Flask لتوليد صفحات HTML ديناميكية من خلال إدخال بيانات متغيرة يتم معالجتها داخل القالب. توفر Jinja مجموعة كبيرة من الأدوات المساعدة مثل الحلقات، الشروط، والمرشحات (Filters)، التي تسمح لك بإجراء عمليات على المتغيرات مباشرة داخل القالب.
ما هي مرشحات Jinja؟
مرشحات Jinja هي عبارة عن دوال تُطبق على القيم في القوالب لتغيير شكلها أو تعديلها قبل عرضها. على سبيل المثال، يمكنك استخدام المرشح |lower لتحويل النص إلى أحرف صغيرة، أو |capitalize لتحويل أول حرف من النص إلى حرف كبير. لكن في بعض الأحيان تكون المرشحات المدمجة في Jinja غير كافية لتلبية متطلبات التطبيق، لذا تسمح Jinja بإنشاء مرشحات مخصصة تناسب احتياجاتك الخاصة.
لماذا نحتاج إلى إنشاء مرشحات Jinja خاصة؟
يواجه مطورو الويب حالات مختلفة تتطلب تحويل أو تنسيق بيانات معقدة لا تدعمه المرشحات الافتراضية. على سبيل المثال:
-
تنسيق تواريخ بأشكال معينة تختلف عن التنسيقات الافتراضية.
-
تعديل نصوص معقدة أو تنظيفها قبل العرض.
-
تحويل قيم رقمية إلى صيغة معينة مثل عملة أو نسبة مئوية.
-
معالجة بيانات من قواعد بيانات تحتاج إلى تحليل أو تغيير معين.
إنشاء مرشحات مخصصة يجعل القوالب أكثر مرونة ونظافة، كما يتيح لك إعادة استخدام الكود بسهولة داخل القوالب المختلفة، ويقلل من التكرار في كود البايثون الخاص بالواجهة الخلفية.
كيفية إنشاء مرشح Jinja خاص في Flask
1. تعريف دالة المرشح
أول خطوة هي كتابة دالة في البايثون تقوم بعملية التحويل أو المعالجة المطلوبة. يجب أن تقبل الدالة قيمة واحدة على الأقل (القيمة التي سيتم تطبيق المرشح عليها)، وقد تقبل قيمًا إضافية في حال كان المرشح يحتاج ذلك.
مثال بسيط على دالة تقوم بتحويل النص إلى صيغة مخصصة:
pythondef reverse_string(value):
return value[::-1]
في هذا المثال، الدالة reverse_string تأخذ نصًا وتُرجعه معكوسًا.
2. تسجيل المرشح داخل تطبيق Flask
بعد تعريف الدالة، تحتاج إلى تسجيلها كمرشح داخل تطبيق Flask باستخدام الكائن app.jinja_env.filters أو باستخدام الديكوريتور @app.template_filter لتكون متاحة داخل قوالب Jinja.
الطريقة الأولى:
pythonapp.jinja_env.filters['reverse'] = reverse_string
الطريقة الثانية:
python@app.template_filter('reverse')
def reverse_string(value):
return value[::-1]
3. استخدام المرشح في القوالب
بعد تسجيل المرشح، يمكن استخدامه داخل قالب Jinja بهذه الصيغة:
jinja{{ "Hello World!" | reverse }}
والنتيجة ستكون:
diff!dlroW olleH
أمثلة عملية لإنشاء مرشحات Jinja مخصصة
مثال 1: تنسيق التاريخ
في كثير من التطبيقات، قد تحتاج إلى عرض التواريخ بطريقة معينة. مثلاً، تحويل تاريخ من صيغة YYYY-MM-DD إلى صيغة عربية أكثر وضوحًا.
pythonfrom datetime import datetime
@app.template_filter('format_date_ar')
def format_date_ar(value, format='%d/%m/%Y'):
if not value:
return ''
if isinstance(value, str):
value = datetime.strptime(value, '%Y-%m-%d')
return value.strftime(format)
في القالب:
jinja{{ user.birthdate | format_date_ar }}
سيتم عرض التاريخ بالتنسيق العربي اليوم/الشهر/السنة.
مثال 2: تحويل الأرقام إلى صيغة العملة
يمكنك إنشاء مرشح يحول الأرقام إلى تنسيق عملة مع إضافة رمز العملة وتنسيق الفواصل.
python@app.template_filter('currency')
def currency_filter(value, symbol='ر.س'):
try:
value = float(value)
except (ValueError, TypeError):
return value
return f"{symbol} {value:,.2f}"
في القالب:
jinja{{ product.price | currency }}
مثال النتيجة: ر.س 1,250.00
التعامل مع مرشحات Jinja المتقدمة
يمكن للمرشحات المخصصة في Jinja قبول معاملات متعددة، مما يزيد من مرونتها وقدرتها على التكيف مع سيناريوهات مختلفة.
مثال: مرشح لإظهار النص بمحدد معين وعدد أحرف
python@app.template_filter('truncate_chars')
def truncate_chars(value, max_length=100, suffix='...'):
if not isinstance(value, str):
value = str(value)
if len(value) <= max_length:
return value
return value[:max_length] + suffix
يمكن تمرير المعاملات داخل القالب:
jinja{{ article.content | truncate_chars(50) }}
دمج المرشحات مع التطبيقات الكبيرة والمتعددة الملفات
في المشاريع الكبيرة التي تحتوي على ملفات متعددة، من الأفضل تنظيم المرشحات في ملف منفصل مخصص لها، ثم استيرادها في ملف التطبيق الرئيسي.
مثال:
-
إنشاء ملف
filters.py:
pythondef reverse_string(value):
return value[::-1]
def currency_filter(value, symbol='ر.س'):
try:
value = float(value)
except (ValueError, TypeError):
return value
return f"{symbol} {value:,.2f}"
-
استيراد المرشحات وتسجيلها في
app.py:
pythonfrom flask import Flask
import filters
app = Flask(__name__)
app.jinja_env.filters['reverse'] = filters.reverse_string
app.jinja_env.filters['currency'] = filters.currency_filter
هذا الأسلوب يسهل صيانة الكود ويجعل التطبيق أكثر تنظيمًا.
نصائح عملية لتحسين استخدام مرشحات Jinja في Flask
-
إبقاء المرشحات بسيطة ومخصصة لمهمة واحدة: تجنب إنشاء مرشحات معقدة تؤدي عدة وظائف؛ كل مرشح يجب أن يقوم بوظيفة واضحة.
-
التأكد من معالجة الأخطاء: يجب أن يكون المرشح قادرًا على التعامل مع قيم غير متوقعة أو فارغة دون تعطل التطبيق.
-
إعادة استخدام المرشحات في القوالب المختلفة: تجنب تكرار الكود عبر إنشاء مرشحات عامة يمكن تطبيقها في عدة أماكن.
-
توثيق المرشحات: كتابة تعليقات واضحة لكل مرشح تشرح وظيفته والمعاملات التي يقبلها.
-
الاختبار: اختبار المرشحات بشكل منفصل قبل استخدامها في التطبيق لتجنب الأخطاء أثناء التشغيل.
الفروق بين المرشحات والدوال المساعدة (Template Globals)
مرشحات Jinja تختلف عن الدوال المساعدة التي يمكن تسجيلها أيضًا لتُستخدم داخل القوالب. المرشحات تُستخدم لتغيير قيمة وتنسيقها، بينما الدوال المساعدة (Template Globals) تُستخدم لأداء عمليات أو إرجاع بيانات دون التغيير المباشر لقيمة معينة.
مقارنة بين مرشحات Jinja واستخدام المعالجة في بايثون
يمكن معالجة البيانات إما في الواجهة الخلفية (بايثون) أو مباشرة داخل القالب باستخدام المرشحات. لكل منهما مزايا وعيوب:
-
المعالجة في بايثون:
-
توفر تحكمًا أكبر وإمكانيات تحليلية متقدمة.
-
يمكن اختبار الكود بشكل أفضل.
-
يقلل من تعقيد القوالب.
-
-
المعالجة في القالب باستخدام المرشحات:
-
يُسهل تعديل طريقة العرض بسرعة.
-
يقلل الحاجة إلى تعديل الكود في الخلفية.
-
يسمح بفصل المنطق البرمجي عن واجهة المستخدم بشكل نسبي.
-
الأفضل هو الموازنة بين الطريقتين بحيث تبقى القوالب نظيفة والخلفية مسؤولة عن المعالجة المعقدة.
حالات استخدام شائعة للمرشحات المخصصة في Flask
| الحالة | وصف الاستخدام | مثال عملي |
|---|---|---|
| تنسيق النصوص | تعديل النصوص مثل التحويل إلى uppercase | `{{ username |
| تنسيق التواريخ | تحويل تاريخ إلى تنسيق معين | `{{ user.created_at |
| تنسيق الأرقام والعملات | عرض الأرقام مع فواصل وعلامات العملة | `{{ product.price |
| تقليم النصوص | قص النصوص الطويلة مع إضافة علامة القطع | `{{ article.summary |
| التحقق من صحة البيانات | تنسيق القيم الفارغة أو غير الصالحة | `{{ value |
تطبيق عملي كامل لإنشاء واستخدام مرشحات Jinja خاصة في Flask
فيما يلي مثال تطبيقي متكامل لإنشاء تطبيق Flask يحتوي على مرشحات مخصصة:
pythonfrom flask import Flask, render_template
from datetime import datetime
app = Flask(__name__)
# مرشح لتحويل النص إلى معكوسه
@app.template_filter('reverse')
def reverse_string(value):
if not isinstance(value, str):
value = str(value)
return value[::-1]
# مرشح لتنسيق التاريخ بصيغة عربية
@app.template_filter('format_date_ar')
def format_date_ar(value, format='%d/%m/%Y'):
if not value:
return ''
if isinstance(value, str):
value = datetime.strptime(value, '%Y-%m-%d')
return value.strftime(format)
# مرشح لتحويل الرقم إلى عملة
@app.template_filter('currency')
def currency_filter(value, symbol='ر.س'):
try:
value = float(value)
except (ValueError, TypeError):
return value
return f"{symbol} {value:,.2f}"
@app.route('/')
def index():
data = {
'username': 'FlaskUser',
'birthdate': '1990-05-15',
'balance': 12345.678
}
return render_template('index.html', data=data)
if __name__ == '__main__':
app.run(debug=True)
محتوى قالب index.html:
jinjaمرشحات Jinja مخصصة مرحبا {{ data.username | reverse }}
تاريخ الميلاد: {{ data.birthdate | format_date_ar }}
الرصيد: {{ data.balance | currency }}
عند تشغيل التطبيق، ستلاحظ كيف تم تطبيق المرشحات المخصصة على البيانات المعروضة.
الخلاصة
إنشاء مرشحات Jinja مخصصة في تطبيقات Flask يُعد من الأدوات القوية التي تعزز من قدرات المطور على تقديم محتوى ديناميكي بشكل أنيق ومنظم، مع توفير إمكانية إعادة استخدام الكود وتحسين جودة القوالب. من خلال التعرف على كيفية بناء هذه المرشحات، تسجيلها، واستخدامها بشكل صحيح، يمكن لأي مطور بناء تطبيقات أكثر مرونة وقابلية للصيانة.
المرشحات لا تُغني عن المعالجة الخلفية المعقدة، لكنها تكملها بتوفير واجهة سهلة وسلسة لتحويل البيانات قبل العرض، مما يؤدي إلى تحسين تجربة المستخدم وكفاءة التطوير.

