كيف تستخدم القالبات في تطبيق Flask

اختار المؤلف مؤسسة الصندوق الحر ومفتوح المصدر لتلقي تبرع كجزء من برنامج Write for DOnations.

مقدمة

Flask هو إطار عمل ويب خفيف الوزن بلغة Python يوفر أدوات وميزات مفيدة لإنشاء تطبيقات ويب بلغة Python.

عند تطوير تطبيق ويب، من المهم فصل منطق الأعمال عن منطق العرض. منطق الأعمال هو ما يتعامل مع طلبات المستخدم ويتحدث مع قاعدة البيانات لبناء استجابة مناسبة. منطق العرض هو كيفية تقديم البيانات للمستخدم، عادةً باستخدام ملفات HTML لبناء الهيكل الأساسي لصفحة الاستجابة الويب، وأنماط CSS لتصميم مكونات HTML. على سبيل المثال، في تطبيق وسائل التواصل الاجتماعي، قد تحتوي على حقل اسم المستخدم وحقل كلمة المرور التي يمكن عرضها فقط عندما لا يكون المستخدم مسجل الدخول. إذا كان المستخدم مسجل الدخول، يتم عرض زر تسجيل الخروج بدلاً من ذلك. هذا هو منطق العرض. إذا قام المستخدم بكتابة اسم المستخدم وكلمة المرور، يمكنك استخدام Flask لتنفيذ منطق الأعمال: تستخرج البيانات (اسم المستخدم وكلمة المرور) من الطلب، وتسجيل الدخول للمستخدم إذا كانت البيانات صحيحة أو الرد برسالة خطأ. كيفية عرض رسالة الخطأ سيتم التعامل معها بواسطة منطق العرض.

في Flask، يمكنك استخدام لغة Jinja لتصيير قوالب HTML. القالب هو ملف يمكن أن يحتوي على محتوى ثابت وديناميكي. عندما يطلب المستخدم شيئًا من تطبيقك (مثل صفحة الفهرس أو صفحة تسجيل الدخول)، تسمح لك Jinja بالرد بقالب HTML حيث يمكنك استخدام العديد من الميزات التي لا تتوفر في HTML القياسي، مثل المتغيرات، عبارات if، حلقات for، الفلاتر، ووراثة القوالب. تسمح لك هذه الميزات بكتابة صفحات HTML سهلة الصيانة بكفاءة. كما تقوم Jinja تلقائيًا بالتخلص من HTML لمنع هجمات Cross-Site Scripting (XSS).

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

المتطلبات الأساسية

الخطوة 1 — تقديم قالب واستخدام المتغيرات

تأكد من تفعيل بيئتك وتثبيت Flask، ثم يمكنك البدء في بناء تطبيقك. الخطوة الأولى هي عرض رسالة ترحيب للزوار على الصفحة الرئيسية. ستستخدم دالة المساعد render_template() الخاصة بـ Flask لتقديم قالب HTML كاستجابة. سترى أيضًا كيفية تمرير المتغيرات من جانب تطبيقك إلى قوالبك.

أولاً، في دليل flask_app الخاص بك، افتح ملفًا باسم app.py للتحرير. استخدم nano أو محرر النصوص المفضل لديك:

  1. nano app.py

أضف الكود التالي داخل ملف app.py:

flask_app/app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello():
    return render_template('index.html')

احفظ وأغلق الملف.

في هذه المجموعة من الأكواد، تقوم باستيراد فئة Flask ودالة render_template() من الحزمة flask. تستخدم فئة Flask لإنشاء مثيل تطبيق Flask الخاص بك المسمى app. ثم تقوم بتعريف دالة العرض (وهي دالة بايثون تُرجع استجابة HTTP) تسمى hello() باستخدام مُزخرف app.route()، الذي يحول الدالة العادية إلى دالة عرض. تستخدم دالة العرض هذه الدالة render_template() لتصيير ملف قالب يسمى index.html.

بعد ذلك، ستحتاج إلى إنشاء ملف قالب index.html في دليل يسمى templates داخل دليل flask_app الخاص بك. يبحث Flask عن القوالب في الدليل templates directory، الذي يسمى templates، لذا فإن الاسم مهم. تأكد من أنك داخل دليل flask_app وقم بتشغيل الأمر التالي لإنشاء دليل templates:

  1. mkdir templates

بعد ذلك، افتح ملف يسمى index.html داخل دليل templates للتحرير. الاسم index.html هنا ليس اسمًا قياسيًا مطلوبًا؛ يمكنك تسميته home.html أو homepage.html أو أي شيء آخر إذا أردت:

  1. nano templates/index.html

أضف رمز HTML التالي داخل ملف index.html:

flask_app/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
</head>
<body>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
</body>
</html>

هنا، قمت بتعيين عنوان، وأضفت رسالة Hello World! كعنوان H1، وأنشأت رسالة Welcome to FlaskApp! كعنوان H2.

احفظ وأغلق الملف.

بينما تكون داخل دليل flask_app مع تفعيل بيئة العمل الافتراضية، أخبر Flask عن التطبيق (app.py في حالتك) باستخدام متغير البيئة FLASK_APP، وقم بتعيين متغير البيئة FLASK_ENV إلى development لتشغيل التطبيق في وضع التطوير والحصول على إمكانية الوصول إلى م除错器. استخدم الأوامر التالية للقيام بذلك (على Windows، استخدم set بدلاً من export):

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

ثم، قم بتشغيل التطبيق باستخدام الأمر flask run:

  1. flask run

مع تشغيل خادم التطوير، قم بزيارة الرابط التالي باستخدام متصفحك:

http://127.0.0.1:5000/

سترى أن عنوان الصفحة هو FlaskApp، والعناوين الأولى هي HTML المُصيَّرة.

في تطبيقات الويب، غالبًا ما تحتاج إلى تمرير البيانات من ملفات Python الخاصة بتطبيقك إلى قوالب HTML. لتوضيح كيفية القيام بذلك في هذا التطبيق، ستقوم بتمرير متغير يحتوي على التاريخ والوقت الحاليين بتوقيت جرينتش إلى قالب index، وستعرض قيمة المتغير في القالب.

اترك الخادم يعمل، وافتح ملف app.py للتحرير في نافذة طرفية جديدة:

  1. nano app.py

استورد وحدة datetime من مكتبة Python القياسية وعدل دالة index() بحيث يبدو الملف كما يلي:

flask_app/app.py
import datetime
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello():
    return render_template('index.html', utc_dt=datetime.datetime.utcnow())

احفظ وأغلق الملف.

هنا قمت باستيراد وحدة datetime وتمرير متغير يسمى utc_dt إلى قالب index.html بقيمة datetime.datetime.utcnow()، وهو التاريخ والوقت الحاليين بتوقيت جرينتش.

بعد ذلك، لعرض قيمة المتغير على صفحة الفهرس، افتح ملف index.html للتحرير:

  1. nano templates/index.html

عدل الملف ليبدو كما يلي:

flask_app/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
</head>
<body>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
    <h3>{{ utc_dt }}</h3>
</body>
</html>

احفظ وأغلق الملف.

لقد أضفت عنوان H3 مع المحدد الخاص {{ ... }} لطباعة قيمة المتغير utc_dt.

افتح متصفحك وزر صفحة الفهرس:

http://127.0.0.1:5000/

سترى صفحة مشابهة للصورة التالية:

لقد قمت الآن بإنشاء صفحة فهرس باستخدام قالب HTML في تطبيق Flask الخاص بك، وعرضت قالبًا، ومررت وعرضت قيمة متغير. الخطوة التالية هي تجنب تكرار الكود من خلال استخدام توارث القوالب.

الخطوة 2 — استخدام توارث القوالب

في هذه الخطوة، ستقوم بإنشاء قالب أساسي يحتوي على المحتوى الذي يمكن مشاركته مع قوالبك الأخرى. ستقوم بتحرير قالب الفهرس ليرث من القالب الأساسي. ثم، ستقوم بإنشاء صفحة جديدة ستكون هي صفحة “حول” لتطبيقك، حيث يمكن للمستخدمين العثور على مزيد من المعلومات حول تطبيقك.

القالب الأساسييحتوي على مكونات HTML التي تُشارك عادةً بين جميع القوالب الأخرى، مثل عنوان التطبيق وشريط التنقل والفواتير.

أولاً، افتح ملفًا جديدًا يسمى base.html للتحرير داخل دليل القوالب الخاص بك:

  1. nano templates/base.html

اكتب الكود التالي داخل ملف base.html الخاص بك:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="#">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

احفظ وأغلق الملف.

معظم الكود في هذا الملف هو HTML قياسي، عنوان، بعض التصميم لروابط التنقل، شريط تنقل برابطين، واحد لصفحة الفهرس والآخر لصفحة “حول” التي لم يتم إنشاؤها بعد، و<div> لمحتوى الصفحة. (الروابط لا تعمل بعد؛ الخطوة التالية ستوضح كيفية الربط بين الصفحات).

ومع ذلك، الأجزاء المميزة التالية محددة لمحرك قوالب Jinja:

  • {% block title %} {% endblock %}: كتلة تعمل كعنصر نائب للعنوان. ستستخدمه لاحقًا في قوالب أخرى لتوفير عنوان مخصص لكل صفحة في تطبيقك دون إعادة كتابة قسم <head> بأكمله في كل مرة.

  • {% block content %} {% endblock %}: كتلة أخرى ستُستبدل بمحتوى يعتمد على القالب الفرعي (قالب يرث من base.html) الذي سيتجاوزها.

الآن بعد أن أصبح لديك قالب أساسي، يمكنك الاستفادة منه باستخدام الوراثة. افتح ملف index.html:

  1. nano templates/index.html

ثم استبدل محتوياته بما يلي:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Index {% endblock %}</h1>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
    <h3>{{ utc_dt }}</h3>
{% endblock %}

هنا، تستخدم العلامة `{% extends %}` للوراثة من قالب `base.html`. ثم تمتدها عن طريق استبدال كتلة `content` في القالب الأساسي بما هو داخل كتلة `content` في الكتلة البرمجية السابقة.

تحتوي كتلة المحتوى هذه على علامة `<h1>` مع النص `Index` داخل كتلة العنوان، التي بدورها تستبدل الكتلة الأصلية `title` في قالب `base.html` بالنص `Index` بحيث يصبح العنوان الكامل `Index - FlaskApp`. بهذه الطريقة، يمكنك تجنب تكرار نفس النص مرتين، حيث تعمل كعنوان للصفحة وكعنوان يظهر تحت شريط التنقل الموروث من القالب الأساسي.

ثم لديك بعض العناوين الأخرى: عنوان `<h1>` بالنص `Hello World!`، وعنوان `<h2>`، وعنوان `<h3>` يحتوي على قيمة المتغير `utc_dt`.

الوراثة القالبية تمنحك القدرة على إعادة استخدام كود HTML الذي لديك في قوالب أخرى (`base.html` في هذه الحالة) دون الحاجة إلى تكراره في كل مرة يكون مطلوبًا.

احفظ وأغلق الملف وقم بتحديث صفحة الفهرس في متصفحك. ستبدو الصفحة كالتالي:

بعد ذلك، ستنشئ صفحة “حول”. افتح ملف `app.py` لإضافة طريقة جديدة:

  1. nano app.py

أضف الطريقة التالية في نهاية الملف:

flask_app/app.py

# ...
@app.route('/about/')
def about():
    return render_template('about.html')

هنا تستخدم الديكور app.route() لإنشاء دالة العرض المسماة about(). فيها، تقوم بإرجاع نتيجة إستدعاء الدالة render_template() مع اسم ملف القالب about.html كوسيطة.

احفظ وأغلق الملف.

افتح ملف قالب يسمى about.html للتحرير:

  1. nano templates/about.html

أضف الكود التالي إلى الملف:

flask_app/templates/about.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} About {% endblock %}</h1>
    <h3>FlaskApp is a Flask web application written in Python.</h3>
{% endblock %}

هنا، ترث من القالب الأساسي باستخدام الوسم extends، وتستبدل كتلة content الخاصة بالقالب الأساسي بوسم <h1> يعمل أيضًا كعنوان الصفحة، وتضيف وسم <h3> ببعض المعلومات حول التطبيق.

احفظ وأغلق الملف.

مع تشغيل خادم التطوير، قم بزيارة الرابط التالي باستخدام متصفحك:

http://127.0.0.1:5000/about

سترى صفحة مشابهة للتالي:

لاحظ كيف تم توريث شريط التنقل وجزء من العنوان من القالب الأساسي.

لقد قمت الآن بإنشاء قالب أساسي واستخدمته في صفحتك الرئيسية وصفحة “حول” لتجنب تكرار الكود. الروابط في شريط التنقل لا تفعل شيئًا في هذه المرحلة. في الخطوة التالية، ستتعلم كيفية الربط بين الطرق في قوالبك عن طريق إصلاح روابط شريط التنقل.

الخطوة 3 — الربط بين الصفحات

في هذه الخطوة، ستتعلم كيفية الارتباط بين الصفحات في قوالبك باستخدام دالة المساعد url_for(). ستضيف رابطين إلى شريط التنقل في قالبك الأساسي، أحدهما لصفحة الفهرس والآخر لصفحة “من نحن”.

أولاً، افتح قالبك الأساسي للتحرير:

  1. nano templates/base.html

قم بتحرير الملف ليبدو كما يلي:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('hello') }}">FlaskApp</a>
        <a href="{{ url_for('about') }}">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

هنا، تستخدم الدالة الخاصة url_for() التي ستعيد عنوان URL لدالة العرض التي تقدمها. الرابط الأول يرتبط بمسار دالة العرض hello() (وهي صفحة الفهرس). الرابط الثاني يرتبط بمسار دالة العرض about(). لاحظ أنك تمرر اسم دالة العرض، وليس المسار (/ أو /about).

استخدام دالة url_for() لبناء عناوين URL يساعدك على إدارة العناوين بشكل أفضل. إذا قمت بترميز عناوين URL بشكل ثابت، فإن الروابط الخاصة بك ستتعطل إذا قمت بتحرير المسارات. مع url_for() يمكنك تعديل المسارات والتأكد من أن الروابط ستعمل كما هو متوقع. تتعامل دالة url_for() أيضًا مع أشياء أخرى مثل التهرب من الأحرف الخاصة.

احفظ وأغلق الملف.

الآن انتقل إلى صفحة الفهرس وجرب الروابط في شريط التنقل. سترى أنها تعمل كما هو متوقع.

تعلمت كيفية استخدام وظيفة url_for() للارتباط بمسارات أخرى في قوالبك. بعد ذلك، ستضيف بعض العبارات الشرطية للتحكم في ما يتم عرضه في قوالبك بناءً على الشروط التي تحددها، واستخدام حلقات for في قوالبك لعرض عناصر القائمة.

الخطوة 4 — استخدام العبارات الشرطية والحلقات

في هذه الخطوة، ستستخدم عبارات if في قوالبك للتحكم في ما يتم عرضه بناءً على شروط معينة. ستستخدم أيضًا حلقات for للمرور عبر قوائم بايثون وعرض كل عنصر في القائمة. ستضيف صفحة جديدة تعرض التعليقات في قائمة. التعليقات التي لها رقم فهرس زوجي سيكون لها خلفية زرقاء، والتعليقات ذات الرقم الفهرسي الفردي سيتم عرضها بخلفية رمادية.

أولاً، ستنشئ مسارًا لصفحة التعليقات. افتح ملف app.py للتحرير:

  1. nano app.py

أضف المسار التالي في نهاية الملف:

flask_app/app.py

# ...

@app.route('/comments/')
def comments():
    comments = ['This is the first comment.',
                'This is the second comment.',
                'This is the third comment.',
                'This is the fourth comment.'
                ]

    return render_template('comments.html', comments=comments)

في المسار أعلاه، لديك قائمة بايثون تسمى comments تحتوي على أربعة عناصر. (عادةً ما تأتي هذه التعليقات من قاعدة بيانات في سيناريو العالم الحقيقي بدلاً من أن تكون مبرمجة بهذه الطريقة كما فعلت هنا.) تقوم بإرجاع ملف قالب يسمى comments.html في السطر الأخير، مع تمرير متغير يسمى comments يحتوي على القائمة إلى ملف القالب.

احفظ وأغلق الملف.

بعد ذلك، افتح ملفّ comments.html جديد داخل دليل templates للتحرير:

  1. nano templates/comments.html

أضف الكود التالي إلى الملف:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
        <div style="padding: 10px; background-color: #EEE; margin: 20px">
            <p style="font-size: 24px">{{ comment }}</p>
        </div>
        {% endfor %}
    </div>
{% endblock %}

هنا، تمدد القالب base.html وتستبدل محتويات الكتلة content. أولاً، تستخدم عنوان <h1> يعمل أيضاً كعنوان الصفحة.

تستخدم حلقة for في Jinja في السطر {% for comment in comments %} للمرور عبر كل تعليق في قائمة comments (التي يتم تخزينها في المتغير comment). تعرض التعليق في الوسم <p style="font-size: 24px">{{ comment }}</p> بنفس الطريقة التي تعرض فيها متغيرًا عاديًا في Jinja. تشير إلى نهاية الحلقة for باستخدام الكلمة الرئيسية {% endfor %}. هذا مختلف عن طريقة بناء حلقات for في Python لأنه لا يوجد تصحيح بيئي خاص في قوالب Jinja.

احفظ وأغلق الملف.

مع تشغيل خادم التطوير، افتح متصفحك وزر صفحة التعليقات:

http://127.0.0.1:5000/comments

سترى صفحة مشابهة لما يلي:

الآن ستستخدم عبارة الشرط if في قوالبك عن طريق عرض التعليقات ذات الرقم الفهرسي الفردي بخلفية رمادية، والتعليقات ذات الرقم الفهرسي الزوجي بخلفية زرقاء.

افتح قالب comments.html للتحرير:

  1. nano templates/comments.html

عدله ليبدو كما يلي:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index % 2 == 0 %}
                {% set bg_color = '#e6f9ff' %}
            {% else %}
                {% set bg_color = '#eee' %}
            {% endif %}

            <div style="padding: 10px; background-color: {{ bg_color }}; margin: 20px">
                <p>#{{ loop.index }}</p>
                <p style="font-size: 24px">{{ comment }}</p>
            </div>
        {% endfor %}
    </div>
{% endblock %}

مع هذا التعديل الجديد، أضفت تعبير if في السطر {% if loop.index % 2 == 0 %}. المتغير loop هو متغير خاص في Jinja يمنحك الوصول إلى معلومات حول الحلقة الحالية. هنا تستخدم loop.index للحصول على فهرس العنصر الحالي، والذي يبدأ من 1، وليس 0 كما في قوائم بايثون.

يتحقق تعبير if هنا مما إذا كان الفهرس زوجيًا باستخدام عامل التشغيل %. يتحقق من باقي قسمة الرقم الفهرسي على 2؛ إذا كان الباقي 0 فهذا يعني أن الرقم الفهرسي زوجي، وإلا فإن الرقم الفهرسي فردي. تستخدم العلامة {% set %} لتعريف متغير يسمى bg_color. إذا كان الرقم الفهرسي زوجيًا، تضبطه على لون أزرق، وإلا إذا كان الرقم الفهرسي فرديًا، تضبط المتغير bg_color إلى رمادي. ثم تستخدم المتغير bg_color لتعيين لون خلفية لعلامة <div> التي تحتوي على التعليق. فوق نص التعليق، تستخدم loop.index لعرض الرقم الفهرسي الحالي في علامة <p>.

احفظ وأغلق الملف.

افتح متصفحك وزر صفحة التعليقات:

http://127.0.0.1:5000/comments

سترى صفحة التعليقات الجديدة:

كانت هذه عرضًا لكيفية استخدام تعبير if. ولكن يمكنك أيضًا تحقيق التأثير نفسه باستخدام المساعد الخاص loop.cycle() في Jinja. لتوضيح ذلك، افتح ملف comments.html:

  1. nano templates/comments.html
flask_app/templates/comments.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            <div style="padding: 10px;
                        background-color: {{ loop.cycle('#EEE', '#e6f9ff') }};
                        margin: 20px">
                <p>#{{ loop.index }}</p>
                <p style="font-size: 24px">{{ comment }}</p>
            </div>
        {% endfor %}
    </div>
{% endblock %}

هنا، قمت بإزالة عبارة if/else واستخدمت المساعد loop.cycle('#EEE', '#e6f9ff') للتناوب بين اللونين. ستكون قيمة background-color #EEE في أحد الأوقات و #e6f9ff في آخر.

احفظ الملف وأغلقه.

افتح صفحة التعليقات في متصفحك، قم بتحديثها، وسترى أن هذا له نفس تأثير عبارة if.

يمكنك استخدام عبارات if لأغراض متعددة، بما في ذلك التحكم في ما يتم عرضه على الصفحة. على سبيل المثال، لعرض جميع التعليقات باستثناء الثاني، يمكنك استخدام عبارة if مع الشرط loop.index != 2 لاستبعاد التعليق الثاني.

افتح قالب التعليقات:

  1. nano templates/comments.html

وقم بتحريره ليبدو كالتالي:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment }}</p>
                </div>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

هنا، تستخدم {% if loop.index != 2 %} لعرض التعليقات التي لا يساوي فهرسها 2، مما يعني جميع التعليقات باستثناء الثاني. كما تستخدم قيمة ثابتة للون الخلفية بدلاً من المساعد loop.cycle() لتبسيط الأمور، والباقي لم يتغير. تنتهي عبارة if باستخدام {% endif %}.

احفظ الملف وأغلقه.

قم بتحديث صفحة التعليقات وسترى أن التعليق الثاني غير معروض.

الآن تحتاج إلى إضافة رابط يأخذ المستخدمين إلى صفحة التعليقات في شريط التنقل. افتح القالب الأساسي للتحرير:

  1. nano templates/base.html

قم بتعديل محتويات الوسم `<nav>` بإضافة رابط `<a>` جديد إليه:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('hello') }}">FlaskApp</a>
        <a href="{{ url_for('comments') }}">Comments</a>
        <a href="{{ url_for('about') }}">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

هنا، تستخدم الدالة `url_for()` للارتباط بدالة العرض `comments()`.

احفظ الملف وأغلقه.

ستحصل شريط التنقل الآن على رابط جديد يرتبط بصفحة التعليقات.

لقد استخدمت عبارات `if` في قوالبك للتحكم في ما يتم عرضه بناءً على شروط معينة. استخدمت حلقات `for` للمرور عبر قوائم بايثون وعرض كل عنصر في القائمة، وتعلمت عن المتغير الخاص `loop` في Jinja. بعد ذلك، ستستخدم مرشحات Jinja للتحكم في كيفية عرض بيانات المتغير.

الخطوة 5 — استخدام المرشحات

في هذه الخطوة، ستتعلم كيفية استخدام مرشحات Jinja في قوالبك. ستستخدم المرشح `upper` لتحويل التعليقات التي أضفتها في الخطوة السابقة إلى أحرف كبيرة، وستستخدم المرشح `join` لدمج تسلسل من السلاسل النصية إلى سلسلة نصية واحدة، وستتعلم كيفية عرض كود HTML موثوق دون تهجئته باستخدام المرشح `safe`.

أولاً، ستحول التعليقات في صفحة التعليقات إلى أحرف كبيرة. افتح قالب `comments.html` للتحرير:

  1. nano templates/comments.html

قم بتعديله ليصبح كالتالي:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

هنا، قمت بإضافة upper فلتر باستخدام رمز القطعة (|). سيقوم هذا بتعديل قيمة المتغير comment لتكون بأحرف كبيرة.

احفظ وأغلق الملف.

مع تشغيل خادم التطوير، افتح صفحة التعليقات باستخدام متصفحك:

http://127.0.0.1:5000/comments

يمكنك رؤية أن التعليقات جميعها بأحرف كبيرة بعد تطبيق الفلتر.

يمكن للفلاتر أيضًا أن تأخذ وسائط في قوسين. لتوضيح ذلك، ستستخدم الفلتر join لدمج جميع التعليقات في قائمة comments.

افتح قالب التعليقات:

  1. nano templates/comments.html

عدله ليبدو كالتالي:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            <p>{{ comments | join(" | ") }}</p>
        </div>
    </div>
{% endblock %}

هنا قمت بإضافة علامة <hr> وعلامة <div> حيث تقوم بدمج جميع التعليقات في قائمة comments باستخدام الفلتر join().

احفظ وأغلق الملف.

قم بتحديث صفحة التعليقات وسترى صفحة مشابهة للتالي:

كما ترى، يتم عرض قائمة comments مع فصل التعليقات برمز القطعة، وهو ما قمت بتمريره إلى الفلتر join().

مرشح آخر مهم هو مرشح safe، الذي يسمح لك بعرض HTML موثوق على المتصفح. لتوضيح ذلك، ستضيف بعض النصوص التي تحتوي على علامة HTML إلى قالب التعليقات الخاص بك باستخدام محدد Jinja {{ }}. في سيناريو حقيقي، سيأتي هذا كمتغير من الخادم. ثم ستقوم بتحرير وسيطة join() لتكون علامة <hr> بدلاً من رمز الأنبوب.

افتح قالب التعليقات:

  1. nano templates/comments.html

عدله ليبدو كالتالي:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            {{ "<h1>COMMENTS</h1>" }}
            <p>{{ comments | join(" <hr> ") }}</p>
        </div>
    </div>
{% endblock %}

هنا، قمت بإضافة القيمة "<h1>COMMENTS</h1>" وغيرت وسيطة الضم لتكون علامة <hr>.

احفظ وأغلق الملف.

قم بتحديث صفحة التعليقات وسترى صفحة مشابهة للتالي:

كما ترى، لم يتم عرض علامات HTML. هذه ميزة أمانية في Jinja، لأن بعض علامات HTML يمكن أن تكون ضارة وقد تؤدي إلى هجوم Cross Site Scripting (XSS). يجب أن تسمح فقط بعرض HTML موثوق في المتصفح.

لعرض علامات HTML أعلاه، افتح ملف قالب التعليقات:

  1. nano templates/comments.html

عدله بإضافة مرشح safe:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            {{ "<h1>COMMENTS</h1>" | safe }}
            <p>{{ comments | join(" <hr> ") | safe }}</p>
        </div>
    </div>
{% endblock %}

يمكنك أن ترى أنه يمكنك أيضًا تسلسل المرشحات كما في السطر <p>{{ comments | join(" <hr> ") | safe }}</p>. يتم تطبيق كل مرشح على نتيجة التصفية السابقة.

احفظ وأغلق الملف.

قم بتحديث صفحة التعليقات وسترى أن علامات HTML الآن تظهر كما هو متوقع:

تحذير: استخدام عامل التصفية safe على HTML من مصادر بيانات غير معروفة قد يفتح تطبيقك لهجمات XSS. لا تستخدمه إلا إذا كان HTML الذي تقوم بعرضه من مصدر موثوق.

لمزيد من المعلومات، تفقد قائمة عوامل التصفية المدمجة في Jinja.

لقد تعلمت الآن كيفية استخدام عوامل التصفية في قوالب Jinja لتعديل قيم المتغيرات. بعد ذلك، ستقوم بدمج مجموعة أدوات Bootstrap لتصميم تطبيقك.

الخطوة 6 — دمج Bootstrap

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

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

لاستخدام Bootstrap، ستحتاج إلى إضافته إلى القالب الأساسي حتى تتمكن من استخدامه في جميع القوالب الأخرى.

افتح قالب base.html الخاص بك للتحرير:

  1. nano templates/base.html

عدله ليبدو كما يلي:

flask_app/templates/base.html
<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">

    <title>{% block title %} {% endblock %} - FlaskApp</title>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
        <a class="navbar-brand" href="{{ url_for('hello') }}">FlaskApp</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('comments') }}">Comments</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('about') }}">About</a>
            </li>
        </ul>
        </div>
    </div>
    </nav>
    <div class="container">
        {% block content %} {% endblock %}
    </div>

    <!-- Optional JavaScript -->

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>

  </body>
</html>

معظم الكود أعلاه هو من Boilerplate Bootstrap المطلوب لاستخدامه. لديك بعض علامات meta، ورابط إلى ملف CSS لـ Bootstrap في قسم <head>، وفي الأسفل لديك رابط إلى JavaScript اختياري. الأجزاء المبينة من الكود تحتوي على كود Jinja الموضح في الخطوات السابقة. لاحظ كيف تستخدم علامات وفئات CSS محددة لإخبار Bootstrap كيفية عرض كل عنصر.

في علامة <nav> أعلاه، لديك علامة <a> بفئة navbar-brand، التي تحدد رابط العلامة التجارية في شريط التنقل. داخل علامة <ul class="navbar-nav">، لديك عناصر شريط التنقل العادية داخل علامة <a> في علامة <li>.

لمعرفة المزيد حول هذه العلامات وفئات CSS، انظر مكونات Bootstrap.

احفظ وأغلق الملف.

مع تشغيل خادم التطوير، افتح صفحة الفهرس بمتصفحك:

http://127.0.0.1:5000/

سترى صفحة مشابهة لما يلي:

يمكنك الآن استخدام مكونات Bootstrap لتصميم العناصر في تطبيق Flask الخاص بك في جميع قوالبك.

خاتمة

الآن تعرف كيفية استخدام قوالب HTML في تطبيقك الإنترنتي باستخدام Flask. لقد استخدمت المتغيرات لتمرير البيانات من الخادم إلى القوالب، واستعملت توارث القوالب لتفادي التكرار، وأدرجت عناصر مثل شروط if وحلقات for، ووصلت بين صفحات مختلفة. تعلمت عن المرشحات لتعديل النصوص وعرض HTML موثوق به، ودمجت Bootstrap في تطبيقك.

إذا كنت تود قراءة المزيد عن Flask، تفقد صفحة الموضوع Flask.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-templates-in-a-flask-application