الرسائل الخاطفة Flash messages في تطبيقات Flask


عبدالهادي الديوري

يُوفّر لنا إطار العمل Flask طريقة بسيطة لتنبيه المُستخدم إلى التّغييرات الطّارئة في التّطبيق كتسجيل الدّخول، إضافة مقال، حذف مقال وتسجيل الخروج، ويُمكن ذلك عبر الدّالة flash التّي تُمكّننا من عرض رسالة للمُستخدم تُفيد بأنّ التّغيير قد حدث بنجاح، فمثلا إذا قام بإضافة مقال جديد فسيستقبل رسالة كالتّالي: “أُضيف المقال بنجاح!” وهذه الرّسالة خاطفة (flash) ما يعني بأنّها ستختفي فور إعادة تحميل الصّفحة.

flask-06.png

على سبيل المثال سنقوم بتنبيه المُستخدم إلى أنّ المقال قد أضيف بنجاح بعد إضافته لمقال جديد وبعد التّأكد من أنّ المقال الجديد قد أضيف إلى قاعدة البيانات، وسيكون التّنبيه كالتّالي:

001.png

ملاحظة: التّنسيق متواجد في ملفّ style.css الذي يُمكنك الحصول عليه من هذا الرّابط

يُمكننا أن نقوم بالأمر بالاستعانة بالدّالة flash بعد استيرادها من إطار العمل Flask وبالتّالي يُصبح سطر الاستيراد كالتّالي:

from flask import Flask, render_template, redirect, url_for, request, session, flash

بعدها يُمكننا استعمال الدّالة ببساطة باستدعاء الدّالة وتمرير الرّسالة كسلسلة نصيّة كما يلي :

flash('الرّسالة التّي ترغب بعرضها')

تأكّد فقط من أنّ السّطر متواجد في آخر الدّالة المسؤولة عن المُوجّه، مُباشرة قبل تقديم قالب HTML أو إعادة التّوجيه.

سنُطبّق هذه الطّريقة لنُضيف رسالة لكل العمليّات التّالية:

  • إضافة مقال جديد بنجاح
  • حذف مقال بنجاح
  • التّنبيه إلى أنّ العمليّة تتطلّب تسجيل الدّخول
  • تسجيل الدّخول بنجاح
  • تسجيل الخروج بنجاح
    وبعدها سنقوم بعرض الرّسالة في أعلى صفحة index.html.

إضافة مقال جديد بنجاح

من أجل إضافة الرّسالة التي تُنبّه المُستخدم بأنّ المقال قد أضيف بنجاح سنُضيف سطرا واحدا إلى دالّة الموجّه create:

flash(u'أضيف المقال بنجاح!')

سنُضيفه مُباشرة قبل السّطر المسؤول عن إعادة التّوجيه إلى الصّفحة الرّئيسيّة وبالتّالي تُصبح الدّالة create كالآتي:

def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']
        manage_db.create(title, content)
        flash(u'أضيف المقال بنجاح!')
    return redirect(url_for('home'))

مُلاحظة: تأكّد من استيراد الدّالة flash قبل أن تحفظ الملفّ.

حذف مقال بنجاح

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

def delete(post_id):
    manage_db.delete(post_id)
    flash(u'حُذف المقال بنجاح!')
    return redirect(url_for('home'))

التّنبيه إلى أنّ العمليّة تتطلّب تسجيل الدّخول

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

def login_required(function):
    @wraps(function) 
    def wrapper(*args, **kwargs):
        if 'logged_in' in session:
            return function(*args, **kwargs)
        else:
            flash(u'سجّل دخولك أولا لإجراء هذه العمليّة')
            return redirect(url_for('home'))
    return wrapper

تسجيل الدّخول بنجاح

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

def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if username == "admin" and password == "password":
            session['logged_in'] = True
            flash(u'سُجّل دخولك بنجاح')
        else:
            return redirect(url_for('home'))
    return redirect(url_for('home'))

تسجيل الخروج بنجاح

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

def logout():
    session.pop('logged_in', None)
    flash(u'سُجّل خروجك بنجاح!')
    return redirect(url_for('home'))

عرض الرّسائل في صفحة HTML

بعد أن أضفنا رسالة لكلّ عمليّة، بقيت خطوة عرضها على المتصفّح، ويُمكن ذلك عبر الدّوران على قيم الدّالة get_flashed_messages وعرض كل عنصر على حدى، وذلك باستخدام حلقة for كما عهدنا:

{% for message in get_flashed_messages() %}
    <div class="flash"> {{ message }} </div>
{% endfor %}

أضف الشّيفرة السّابقة إلى الملفّ index.html مُباشرة بعد وسم body واحفظ الملف.
يُمكنك الآن تجربة التّطبيق وإجراء العمليّات السّابقة وستُلاحظ بأنّ رسالة تظهر حسب العمليّة التي أجريتها.

نقل بيانات تسجيل الدّخول إلى إعدادات التّطبيق

حاليا نستعمل السّطر التّالي للتحقق من أنّ بيانات تسجيل الدّخول صحيحة:

if username == "admin" and password == "password"

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

app = Flask(__name__)
app.config['SECRET_KEY'] = "Secret"
app.config['USERNAME']   = "admin"
app.config['PASSWORD']   = "password"

وبعدها سنقوم بتغيير الجملة الشّرطيّة لتُصبح كالتّالي:

if username == app.config['USERNAME'] and password == app.config['PASSWORD']:

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

تخزين الإعدادات في ملفّ مُستقل

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

SECRET_KEY = 'Secret!!!'
USERNAME   = 'admin'
PASSWORD   = 'password'

احفظ الملف وأغلقه، سنحتاج الآن إلى ربط ملفّ الإعدادات مع ملفّ app.py، ويُمكن القيام بذلك عبر إستبدال الأسطر التّالية بسطر واحد:


app.config['SECRET_KEY'] = "Secret"
app.config['USERNAME']   = "admin"
app.config['PASSWORD']   = "password"

ضع السّطر التّالي عوضا عنها:

app.config.from_object('config')

أصبح الآن بإمكاننا تعديل الإعدادات عبر تغيير البيانات داخل الملفّ config.py بطريقة بسيطة ودون التّعامل مع شيفرة التّطبيق الأساسيّة.

إضافة تاريخ لنهاية صلاحية الجلسة

افتراضيّا، يقوم Flask بتسجيل الجلسة طوال مدّة فتح المتصفّح، ما يعني بأنّ تسجيل الدّخول سيكون صالحا لمدّة وجيزة فقط ويجب علينا تغيير هذا الإعداد لكي يبقى المُستخدم مُسجّلا لمدّة أطول، ويُمكنك بعد فهم الطّريقة إضافة خيار “تذكّرني” إلى التّطبيق.

يُمكن أن نقوم بإضافة تاريخ لنهاية صلاحية الجلسة عبر تمكين خيار التّحكم بهذه الميزة وذلك بإضافة السّطر التّالي مباشرة بعد تسجيل الجلسة (أي بعد السّطر session['logged_in'] = True):

session.permanent = True

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

from datetime import timedelta

سنتمكّن الآن من تعيين مُدّة زمنيّة محدّدة لتدمير الجلسة، مثلا لو أردنا حذف الجلسة بعد نصف ساعة يُمكن أن نضيف السّطر التّالي مُباشرة بعد السّطر session.permanent = True:

app.permanent_session_lifetime = timedelta(minutes=30)

ما يعني بأنّ دالّة الموجّه login ستصبح كالتّالي:

def login():
    session['logged_in'] = True
    session.permanent = True
    # Make session last for only 30 min 
    app.permanent_session_lifetime = timedelta(minutes=30)
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if username == "admin" and password == "password":
            session['logged_in'] = True
            flash(u'سُجّل دخولك بنجاح')
        else:
            return redirect(url_for('home'))
    return redirect(url_for('home'))

ويكفي تغيير مُعامل الدّالة timedelta لتغيير مُدّة صلاحيّة الجلسة ويمكن كذلك التحكم في وحدة الزّمن. والتّالي بعض الأمثلة على مُختلف وحدات الزّمن:

timedelta(days=0) # الأيام

timedelta(seconds=0) # الثواني

timedelta(minutes=0) # الدّقائق

timedelta(hours=0) # السّاعات

timedelta(weeks=0) # الأسابيع

 





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن