البرمجة

استخدام Jinja وWTForms في Flask

عرض النّماذج باستخدام Jinja والوصول إلى بيانات نماذج WTForms في تطبيقات Flask

تُعتبر عملية عرض النّماذج الإلكترونية وإدارة البيانات المرسلة من قبل المستخدمين من العمليات الأساسية التي لا غنى عنها في تطوير التطبيقات الويب الحديثة. عند استخدام إطار العمل Flask، الذي يُعد من أشهر أطر العمل بلغة بايثون لتطوير تطبيقات الويب، يصبح التعامل مع النّماذج من خلال مكتبة WTForms ودمجها مع نظام القوالب Jinja حجر الزاوية في بناء واجهات تفاعلية وفعالة. في هذا المقال سيتم استعراض آليات عرض النّماذج باستخدام Jinja، وكيفية الوصول إلى بيانات نماذج WTForms بشكل تفصيلي، مع التركيز على أفضل الممارسات وأبرز التحديات.


مقدمة حول Flask و WTForms و Jinja

يُعَدُّ Flask إطار عمل ويب صغير الحجم ولكنه قوي ومرن يعتمد على لغة البرمجة Python، ويتميز ببساطة البناء، وسهولة التعلم، والقدرة على التوسع. من أهم الأدوات التي تدعم بناء تطبيقات Flask هي مكتبة WTForms، والتي توفر بنية برمجية مهيكلة لإنشاء النّماذج الإلكترونية والتحقق من صحة البيانات المدخلة، إضافة إلى محرك القوالب Jinja، الذي يسمح بإنشاء صفحات HTML ديناميكية باستخدام لغة قوالب مبسطة.

WTForms

WTForms هي مكتبة مستقلة عن Flask تستخدم لتصميم النّماذج الإلكترونية، حيث تسمح بإنشاء حقول متعددة، مع القدرة على التحقق من البيانات المدخلة باستخدام Validators مُدمجة أو مخصصة. تتميز WTForms بسهولة تكاملها مع Flask عبر مكتبة Flask-WTF، التي تربط بين WTForms وإطار العمل وتُضيف ميزات إضافية مثل حماية ضد هجمات CSRF.

Jinja

Jinja هو محرك قوالب يُستخدم في Flask لتمكين المطور من دمج البيانات البرمجية مع صفحات HTML بشكل ديناميكي. تتيح قوالب Jinja استخدام المتغيرات، الحلقات، الشروط، والتوارث بين القوالب، ما يسهّل عملية بناء صفحات ويب منظمة وقابلة للصيانة.


إنشاء النماذج باستخدام WTForms في Flask

يبدأ بناء النّماذج في Flask بتعريف نموذج Form مخصص عبر WTForms. على سبيل المثال، يمكن إنشاء نموذج تسجيل يحتوي على حقول للاسم، البريد الإلكتروني، وكلمة المرور مع التحقق من صحة كل حقل.

python
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, Email, Length class RegistrationForm(FlaskForm): username = StringField('اسم المستخدم', validators=[DataRequired(), Length(min=4, max=25)]) email = StringField('البريد الإلكتروني', validators=[DataRequired(), Email()]) password = PasswordField('كلمة المرور', validators=[DataRequired(), Length(min=6)]) submit = SubmitField('تسجيل')

في هذا المثال، يحتوي النموذج على أربعة حقول: اسم المستخدم، البريد الإلكتروني، كلمة المرور وزر الإرسال. لكل حقل مُحدد Validators لضمان صحة البيانات قبل معالجة الطلب.


عرض النّماذج في قوالب Jinja

بعد إنشاء نموذج WTForms في الجزء الخلفي من التطبيق (Backend)، يتوجب عرض النموذج في واجهة المستخدم (Frontend). يقوم Flask بتمرير النموذج إلى قالب Jinja ليتم عرضه، وذلك عبر استخدام توابع render_template.

تمرير النموذج إلى القالب

في ملف التطبيق الرئيسي، يتم إنشاء كائن النموذج وتمريره إلى القالب:

python
from flask import Flask, render_template, redirect, url_for app = Flask(__name__) app.config['SECRET_KEY'] = 'your_secret_key_here' @app.route('/register', methods=['GET', 'POST']) def register(): form = RegistrationForm() if form.validate_on_submit(): # معالجة البيانات، مثل حفظ المستخدم في قاعدة البيانات return redirect(url_for('success')) return render_template('register.html', form=form)

في هذا المثال، إذا تم إرسال البيانات وتم تمريرها بنجاح عبر التحقق validate_on_submit()، يتم إعادة توجيه المستخدم إلى صفحة نجاح. أما في حالة العرض العادي للنموذج (GET) أو وجود أخطاء، يتم عرض النموذج في قالب register.html.

كتابة قالب Jinja لعرض النموذج

في قالب Jinja، يتم استخدام المتغير form الممرر من الفيو (View) لعرض الحقول بشكل ديناميكي. المثال التالي يوضح كيفية كتابة قالب HTML يعرض النموذج:

html
html> <html lang="ar"> <head> <meta charset="UTF-8"> <title>تسجيل مستخدم جديدtitle> head> <body> <h1>نموذج التسجيلh1> <form method="POST" action=""> {{ form.hidden_tag() }} <p> {{ form.username.label }}<br> {{ form.username(size=32) }}<br> {% for error in form.username.errors %} <span style="color: red;">{{ error }}span><br> {% endfor %} p> <p> {{ form.email.label }}<br> {{ form.email(size=32) }}<br> {% for error in form.email.errors %} <span style="color: red;">{{ error }}span><br> {% endfor %} p> <p> {{ form.password.label }}<br> {{ form.password(size=32) }}<br> {% for error in form.password.errors %} <span style="color: red;">{{ error }}span><br> {% endfor %} p> <p>{{ form.submit() }}p> form> body> html>

شرح المكونات في قالب Jinja

  • form.hidden_tag(): تُستخدم لطباعة الحقول المخفية مثل رمز الحماية من هجمات CSRF.

  • form.field.label: لعرض تسمية الحقل.

  • form.field(size=32): لعرض الحقل مع ضبط حجم الإدخال.

  • حلقة for error in form.field.errors: لعرض رسائل الأخطاء الخاصة بكل حقل بشكل واضح تحت الحقل.

  • form.submit(): لعرض زر الإرسال.

هذه الطريقة في العرض تضمن مرونة كاملة في التحكم بالمظهر عبر HTML وCSS، مع الحفاظ على وظائف التحقق من الصحة وإدارة البيانات في الخلفية.


الوصول إلى بيانات النماذج والتحقق منها في Flask

تُعتبر مرحلة معالجة البيانات المُرسلة عبر النموذج من أهم الخطوات التي تلي عملية العرض، حيث يجب على المطور الوصول إلى قيم الحقول المدخلة من قبل المستخدمين والتعامل معها بشكل آمن وفعّال.

طرق التحقق من صحة البيانات

  • validate_on_submit(): طريقة تدمج بين التحقق من طلب POST والتحقق من صحة البيانات وفقاً للValidators المعرفة في النموذج.

  • form.errors: قاموس يحتوي على الأخطاء المرتبطة بكل حقل في حالة وجود أخطاء تحقق.

استرجاع بيانات الحقول

يمكن الوصول إلى بيانات الحقول عبر خاصية data لكل حقل من حقول النموذج. مثال:

python
if form.validate_on_submit(): username = form.username.data email = form.email.data password = form.password.data # يمكن معالجة هذه البيانات هنا، مثل إدخالها إلى قاعدة بيانات

بهذه الطريقة، يتم ضمان استلام القيم التي تم التحقق من صحتها.


التحقق من صحة النماذج المتقدمة

تدعم WTForms مجموعة واسعة من الـ Validators التي تضمن تحقيق شروط تحقق معقدة، ومن هذه الشروط:

  • DataRequired: التأكد من عدم ترك الحقل فارغًا.

  • Email: التحقق من صحة صيغة البريد الإلكتروني.

  • Length: التأكد من طول النص ضمن حدود معينة.

  • EqualTo: للتحقق من تطابق حقلين (مثلاً لتأكيد كلمة المرور).

  • Regexp: للتحقق من النصوص عبر تعبيرات منتظمة.

يمكن أيضاً إنشاء Validators مخصصة حسب متطلبات التطبيق. مثال على Validator مخصص:

python
from wtforms.validators import ValidationError def username_exists(form, field): if User.query.filter_by(username=field.data).first(): raise ValidationError('اسم المستخدم هذا موجود مسبقًا.')

ويتم إضافته إلى حقل اسم المستخدم:

python
username = StringField('اسم المستخدم', validators=[DataRequired(), username_exists])

التعامل مع النماذج المركبة والمكررة

في بعض التطبيقات، تحتاج النماذج إلى أن تحتوي على حقول معقدة أو مجموعات من الحقول مثل قوائم أو حقول متكررة. WTForms تقدم دعماً لذلك عبر:

  • FormField: تضمين نموذج فرعي داخل نموذج رئيسي.

  • FieldList: لإنشاء قائمة من نفس النوع من الحقول أو النماذج الفرعية.

مثال على نموذج يحتوي على قائمة من عناوين البريد الإلكتروني:

python
from wtforms import FieldList, FormField, Form, StringField class EmailForm(Form): email = StringField('البريد الإلكتروني', validators=[Email()]) class ContactForm(FlaskForm): name = StringField('الاسم', validators=[DataRequired()]) emails = FieldList(FormField(EmailForm), min_entries=1, max_entries=5) submit = SubmitField('إرسال')

وهذا يسمح بإنشاء نموذج يحتوي على عدة حقول بريد إلكتروني قابلة للزيادة أو النقصان بشكل ديناميكي.


إدارة الحماية ضد هجمات CSRF في WTForms وFlask

تدعم مكتبة Flask-WTF بشكل تلقائي حماية النماذج من هجمات تزوير الطلبات بين المواقع (Cross-Site Request Forgery – CSRF) عن طريق تضمين رموز مخفية مع كل نموذج والتأكد من صحتها عند استلام البيانات.

يجب تحديد مفتاح سري للتطبيق:

python
app.config['SECRET_KEY'] = 'مفتاح_سري_عشوائي'

ثم تضمين form.hidden_tag() في القالب لعرض الحقول المخفية الخاصة بالتحقق من CSRF.


تنسيق النماذج باستخدام CSS وتحسين تجربة المستخدم

على الرغم من أن WTForms توفر طريقة سهلة لإدارة النماذج، إلا أن التحكم في شكل النموذج يتطلب استخدام CSS وتنسيق مخصص داخل قوالب Jinja. يمكن استخدام مكتبات CSS شهيرة مثل Bootstrap لتجميل النماذج بسرعة.

مثال لتنسيق حقول النموذج باستخدام Bootstrap:

html
<form method="POST" action=""> {{ form.hidden_tag() }} <div class="form-group"> {{ form.username.label(class="form-label") }} {{ form.username(class="form-control") }} {% for error in form.username.errors %} <div class="text-danger">{{ error }}div> {% endfor %} div> <button type="submit" class="btn btn-primary">{{ form.submit.label.text }}button> form>

استخدام هذه الطريقة يُحسّن من تجربة المستخدم ويجعل النماذج أكثر جاذبية وسهولة في التفاعل معها.


مثال كامل لمشروع بسيط باستخدام Flask, WTForms و Jinja

ملف التطبيق (app.py)

python
from flask import Flask, render_template, redirect, url_for from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, Email, Length app = Flask(__name__) app.config['SECRET_KEY'] = 'secret_key_for_csrf_protection' class RegistrationForm(FlaskForm): username = StringField('اسم المستخدم', validators=[DataRequired(), Length(min=4, max=25)]) email = StringField('البريد الإلكتروني', validators=[DataRequired(), Email()]) password = PasswordField('كلمة المرور', validators=[DataRequired(), Length(min=6)]) submit = SubmitField('تسجيل') @app.route('/register', methods=['GET', 'POST']) def register(): form = RegistrationForm() if form.validate_on_submit(): username = form.username.data email = form.email.data password = form.password.data # يمكن إضافة منطق تخزين البيانات في قاعدة البيانات هنا return redirect(url_for('success')) return render_template('register.html', form=form) @app.route('/success') def success(): return "تم التسجيل بنجاح!" if __name__ == '__main__': app.run(debug=True)

قالب التسجيل (templates/register.html)

html
html> <html lang="ar"> <head> <meta charset="UTF-8"> <title>تسجيل مستخدم جديدtitle> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> head> <body> <div class="container mt-5"> <h2>نموذج التسجيلh2> <form method="POST" action=""> {{ form.hidden_tag() }} <div class="mb-3"> {{ form.username.label(class="form-label") }} {{ form.username(class="form-control") }} {% for error in form.username.errors %} <div class="text-danger">{{ error }}div> {% endfor %} div> <div class="mb-3"> {{ form.email.label(class="form-label") }} {{ form.email(class="form-control") }} {% for error in form.email.errors %} <div class="text-danger">{{ error }}div> {% endfor %} div> <div class="mb-3"> {{ form.password.label(class="form-label") }} {{ form.password(class="form-control") }} {% for error in form.password.errors %} <div class="text-danger">{{ error }}div> {% endfor %} div> <button type="submit" class="btn btn-primary">{{ form.submit.label.text }}button> form> div> body> html>

جدول مقارنة بين طرق عرض النماذج وأسلوب التعامل مع البيانات

الخاصية Jinja مع WTForms طرق أخرى (HTML عادي + JavaScript)
التحقق من صحة البيانات يتم على الخادم عبر Validators مدمجة غالبًا على المتصفح فقط، أقل أمانًا
حماية CSRF مدمجة ضمن Flask-WTF بسهولة تتطلب إعدادات إضافية ومكتبات خارجية
سهولة إعادة عرض الأخطاء تلقائية عبر form.field.errors يجب كتابة الكود يدويًا
سهولة التحكم في الشكل كامل عبر HTML و CSS مع دعم Bootstrap يتطلب كتابة JavaScript إضافية لتفاعل أفضل
قابلية التوسع للنماذج المعقدة دعم كامل للنماذج الفرعية والمكررة يحتاج لتصميم هيكلي معقد
تكامل مع قواعد البيانات سهل عبر الحصول على البيانات من form.field.data يحتاج معالجة يدوية وتحويل بيانات

الخاتمة

إطار العمل Flask، عند دمجه مع مكتبة WTForms ومحرك القوالب Jinja، يوفر منظومة متكاملة لبناء النّماذج الإلكترونية بطريقة منظمة، آمنة، وسهلة التخصيص. عرض النّماذج باستخدام Jinja يتيح للمطورين تحكمًا كاملًا في شكل وهيكل النماذج مع إمكانية ربطها بقواعد البيانات بشكل سلس. أما الوصول إلى بيانات النماذج والتحقق منها في الجانب الخلفي عبر WTForms يضمن سلامة البيانات وجودتها قبل أي عملية معالجة أو تخزين. استخدام هذه الأدوات معًا يؤدي إلى بناء تطبيقات ويب عالية الجودة مع تجربة مستخدم متميزة، مع الحفاظ على معايير الأمان وقابلية التطوير.

المصادر:

  1. WTForms Documentation

  2. Flask-WTF Documentation