اذهب إلى المحتوى

تقديم قوالب HTML لدى استخدام المُخطّطات Blueprint في تطبيقات Flask


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

 

مُقدّمة:

بعد أن قمنا بتنظيم ملفّات التّطبيق على حسب الوظيفة باستعمال خاصيّة المُخطّطات، أصبح لدينا اختلاف بسيط في كيفيّة التّعامل مع ملفّات العرض التّي تحتوي على شيفرات HTML وشيفرات مُحرّك القوالب Jinja، وسيكون هناك اختلاف بسيط أيضا في طريقة استخدام الدّالة url_for للرّبط بين المُوجّهات.

main2.png

إنشاء صفحات HTML

بما أنّنا أنشأنا ثلاثة مجلّدات باسم templates لتعدّد أغراضها، فسيتوجّب علينا أن نفهم أولا كل مجلّد ووظيفته.

مسارات المُجلّدات التّي أنشأناها سابقا هي كالآتي:

project/templates/
project/posts/templates/
project/users/templates/

المسار الأول عبارة عن مجلّد رئيسي للقوالب، يُمكنك أن تعتبره مُشتركا مع القوالب الأخرى، فمثلا يُمكن لكل من ملفّات المقالات والمُستخدمين أن يرثوا من ملفّ base.html كما سنوضّح بعد قليل، كما أنّ أي موجّه يُعرّف داخل الملفّ الرّئيسي project/__init__.py له الحق في تقديم الملفّات المُتواجدة في مجلّد القوالب الرّئيسي مُباشرة.

أي أنّك تستطيع تعديل الموجّه الرّئيسي ليُقدّم القالب index.html المتواجد داخل مجلّد project/templates كالآتي:

# project/__init__.py
from flask import Flask, render_template

#...
#...

@app.route('/') # 127.0.0.1:5000/
def index():
    return render_template('index.html') # render project/templates/index.html

لا تنس بأنّنا استردنا أولا الدّالة render_template ثمّ استدعيناها في المُوجّه لتقديم الملفّ index.html.

بنفس الطّريقة سنقوم بتقديم كلّ من ملفّي posts.html الخاصّ بالمقالات و users.html الخاص بالمُستخدمين.

حدّث المُوجّه في مُخطّط المقالات ليُصبح كما يلي:

# project/posts/views.py


from flask import Blueprint, render_template

@posts.route('/') # 127.0.0.1:5000/posts
def index():
    return render_template('posts.html') # render project/posts/templates/posts.html

وهكذا سيكون الموجّه الجديد في المُخطّطات الخاصّة بالمُستخدمين:

# project/users/views.py


from flask import Blueprint, render_template

@users.route('/') # 127.0.0.1:5000/users
def index():
    return render_template('users.html') # render project/users/templates/users.html

هكذا إن طلب الزّائر أي صفحة من الصّفحات الثّلاث فسيُقدّمُ ملفّ HTML المُناسب.

استخدام إطار Bootsrap لتنسيق الصّفحات

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

سنستخدم في هذا المشروع إطار bootsrap 3 الذي يُمكنك تحميله من الموقع الرّسمي وفك الضّغط عن ملفّ zip داخل مجلّد project/static، سأعتمد كذلك على مشروع Bootsrap-rtl لتعريب وتوجيه التّنسيق من اليمين إلى اليسار وسأضعه في مجلّد project/static/css كما سأضع مكتبة jquery داخل مجلّد project/static/css/bootstrap لذا تأكّد من أنّك قد جهّزت كلّ شيء قبل أن تبدأ في استدعاء الملفّات السّاكنة.

بعد تجهيز مُجلّد static ستكون المُجلّدات والملفّات بداخله كما يلي:

project/static/
├── bootstrap
│   ├── css
│   │   └── bootstrap.min.css
│   └── js
│       ├── bootstrap.min.js
│       └── jquery.js
└── css
    ├── bootstrap-rtl.min.css
    └── style.css

قد تكون هناك ملفّات إضافيّة حسب ما قُمت بتنزيله عندما نزّلت إطار العمل Bootstrap، لكنّ الملفّات أعلاه هي الأهم وهي التّي سنحتاج إليها حاليّا.

إذا أردت إضافة ملفّات Javascript أخرى، فيُمكنك إمّا أن تضعها داخل مُجلّد js المُتواجد داخل المُجلّد bootstrap أو أن تُنشئ مُجلّدا جديدا باسم js داخل مُجلّد الملفّات السّاكنة static.

الوراثة في قوالب Jinja2

لنقل بأنّنا نُريد عرض جملة واحدة في كل ملف من ملفات HTML الثلاثة. يُمكن أن أقوم بما يلي في كل ملفّ:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    Hello

</body>
</html>

مع تعويض Hello بالجملة التّي ارغب في عرضها عند طلب كل موجّه.
هذه الطّريقة تعمل بشكل جيّد، لكن ألا تُلاحظ بأنّنا سنُكرّر نفس الأسطر في كلّ ملف؟
عوضا عن تكرار الأسطر في كلّ ملف يُمكننا استعمال مبدأ الوراثة في مجرّك القوالب Jinja.

وللاستفادة من هذا المبدأ في المثال السّابق، يُمكن أن نكتب الأسطر التّي تتكرّر في كل ملف في ملفّ رئيسي واحد يُعتبر القاعدة لجميع الملفّات الأخرى، وهذا هو دور ملفّ project/templates/base.html الذي أنشأناه سابقا، ففيه يُمكننا وضع الأسطر السّابقة مع تخصيص المكان الذي سنستطيع كتابة الجملة الخاصّة بكل ملف فيه.
افتح ملفّ base.html وضع فيه ما يلي:

{#  project/templates/base.html #}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %}</title>
    <script src="{{ url_for("static", filename="bootstrap/js/jquery.js") }}"></script>
    <script src="{{ url_for("static", filename="bootstrap/js/bootstrap.min.js") }}"></script>
    <link rel="stylesheet" href="{{ url_for("static", filename="bootstrap/css/bootstrap.min.css") }}">
    <link rel="stylesheet" href="{{ url_for("static", filename="css/style.css") }}">
    <link rel="stylesheet" href="{{ url_for("static", filename="css/bootstrap-rtl.min.css") }}">
</head>
<body>

     {% block content %} {% endblock %}


</body>
</html>

احفظ الملف وأغلقه.
لاحظ بأنّنا قمنا باستدعاء جميع الملفّات التّي سنحتاج إليها للتّنسيق وإضافة ميّزات أخرى بلغة Javascript، وقُمنا كذلك بوضع كتلة Block باسم title لتعويضها بالعنوان في كل ملفّ، أمّا كتلة content فهي التّي ستُعوّضُ بالمحتوى (كلمة Hello في مثالنا السّابق).

يُمكنك إضافة ملفّات أخرى إلى مُجلّد static، لكن لا تنس أن تقوم باستيرادها في ملفّ base.html لكي تعمل في جميع الصّفحات.

بعد تجهيز الملفّ base.html الذي سيُشكّل قاعدة للملفّات الأخرى، سنُنشئ الآن ثلاثة ملفّات HTML رئيسيّة، وهي كما يلي:

  • ملفّ HTML للصّفحة الرّئيسية (مساره project/templates/index.html ).

  • ملفّ HTML للصّفحة الرّئيسية للمُستخدمين (مساره project/users/templates/users.html).

  • ملفّ المقالات الرّئيسي (مساره project/posts/templates/posts.html).

لملء الملفّات، ضع الشّيفرة التّاليّة في كلّ ملفّ يُمكنك الاستعانة بالمسار المُشار إليه في التّعليق أعلى الشّيفرة للوصول إلى الملفّ بشكل أسرع.

ملفّ الصّفحة الرّئيسية:

{# project/templates/index.html #}

{% extends 'base.html' %}

{% block title %} كلمة  –  الصّفحة الرّئيسية {% endblock %}

{% block content %}

<h1> مرحبا بك في تطبيق كلمة </h1>
{% endblock %}

ملفّ الصّفحة الرّئيسية للمُستخدمين:

{# project/users/templates/users.html #}

{% extends 'base.html' %}

{% block title %} كلمة  – المُستخدمون {% endblock %}

{% block content %}

<h1> الصّفحة الرّئيسية للمُستخدمين  </h1>

{% endblock %}

ملفّ الصّفحة الرّئيسية للمقالات:

{# project/posts/templates/posts.html #}

{% extends 'base.html' %}

{% block title %} كلمة  – المقالات  {% endblock %}

{% block content %}

<h1> الصّفحة الرّئيسية للمقالات </h1>

{% endblock %}

كما ترى عوضا عن تكرار الكثير من شيفرات HTML قمنا ببساطة بإنشاء ملفّ واحد والوراثة منه باستخدام الجملة extends 'base.html' وفي كلّ مكان نضع المحتوى المناسب، وبهذه الطّريقة سنمتلك طريقة ديناميكية لتحديد عنوان ومحتوى كلّ موجّه مرتبط بقالب معيّن، بالإضافة إلى أنّ الملفّات السّاكنة مثل ملفّاتcss و js ستكون مُتاحة في جميع الملفّات التّي ترث من الملّف الرّئيسي base.html.

مُلاحظة: في بعض المشاريع المكتوبة بلغة بايثون وإطار العمل فلاسك، يُمكن أن يُسمّى الملفّ المُشترك باسم layout.html عوضا عن base.html، لكنّ المبدأ هو نفسه.

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

الرّبط بين المُوجّهات باستخدام الدّالة url_for

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

للرّبط بين موجّهات المُخطّطات باستخدام الدّالة url_for، نقوم أولا بوضع اسم المُخطّط ثمّ اسم الدّالة التّي يتم استدعاؤها عند الوصول إلى المُوجّه، وبما أنّنا سمينا هذه الدّوال باسم index فللرّبط بينها يُمكنك أن تقوم بشيء مُشابه لما يلي:

url_for('index') # /
url_for('posts.index') # /posts
url_for('users.index') # /users

لو كانت الدّالة تقبل مُعاملا لتوجّب علينا تمرير قيمته كالآتي:

url_for('posts.post_by_id', post_id = 1)

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

الرّوابط في الصّفحة الرّئيسية:

{# project/templates/index.html #}

<a href="{{ url_for("posts.index") }}"> اضغط هنا للوصول إلى صفحة المقالات </a>
<br>
<a href="{{ url_for("users.index") }}">اضغط هنا للوصول إلى صفحة المُستخدمين</a>

رابط العودة إلى الصّفحة الرّئيسية في صفحة المقالات:

{# project/posts/templates/posts.html #}

<a href="{{ url_for("index") }}">اضغط هنا للعودة إلى الصّفحة الرّئيسيّة</a>

رابط العودة إلى الصّفحة الرّئيسية في صفحة المُستخدمين:

{# project/users/templates/users.html #}

<a href="{{ url_for("index") }}">اضغط هنا للعودة إلى الصّفحة الرّئيسيّة</a>

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

الرّبط بين المُوجّهات مع تمرير مُعاملات للدالّة التّابعة لكل موجّه.

لفهم مبدأ المعاملات أكثر، سنقوم بإضافة موجّه للوصول إلى مقال برقم مُعرّفه في ملفّ project/posts/views.py كما يلي:

# project/posts/views.py

#..
#..


@posts.route('/<int:id>')
def post_by_id(id):
    return render_template('post.html', id = id)

لاحظ بأنّنا خصّصنا المعامل id من نوع int أي عدد صحيح، فإن لم تكن قيمة المُعامل عند الوصول إلى الرّابط عددا صحيحا فإنّ ذلك سيُسبّب خطأ من نوع 404. بمعنى أدق، الرّابط /posts/1 صحيح، أمّا /posts/abc فسيرجع الخطأ ذو الرّقم 404. سنتعرّف على كيفيّة التّعامل مع هذه الأخطاء في درس قادم.

سنضع ما يلي في ملفّ post.html الذي قدّمناه:

{% extends 'base.html' %}

{% block title %} كلمة  – المقال ذو المُعرّف {{ id }}  {% endblock %}

{% block content %}

<h1> صفحة المقال الواحد ذو رقم المُعرّف {{id}} </h1>

<a href="{{ url_for("index") }}">اضغط هنا للعودة إلى الصّفحة الرّئيسيّة</a>

{% endblock %}

لنستخدم الآن الدّالة url_for داخل ملفّ posts.html لضرب مثال على كيفيّة تمرير مُعاملات إلى الدّالة.

أضف ما يلي إلى ملفّ posts.html مُباشرة بعد الوسم <h1>:

<a href="{{url_for("posts.post_by_id", id=1)}}">
<h2> رابط المقال الأول </h2>
</a>

<a href="{{url_for("posts.post_by_id", id=2)}}">
<h2> رابط المقال الثّاني </h2>
</a>

الآن، إن دخلت إلى صفحة المقالات فستلاحظ رابطين لمقالين وهميّين، الأول رقم معرّفه 1 والآخر رقم مُعرّفه 2، ورابط المقالين كالتّالي:

http://127.0.0.1:5000/posts/1

http://127.0.0.1:5000/posts/2

يُمكنك كذلك زيارة صفحات أخرى عبر تغيير قيمة رقم المُعرّف إلى أي عدد صحيح، والتّالي بعض الأمثلة:

http://127.0.0.1:5000/posts/99 

http://127.0.0.1:5000/posts/232 

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

خاتمة

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


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

أفضل التعليقات

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



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...