یادگیری فلاسک؛ وراثت اُلگو در Jinja - بخش پنجم

در بخش قبل یاد گرفتیم که چطور اولین صفحه HTML خود را با استفاده از موتور Jinja بارگذاری و آن را روی مرورگر نشان دهیم؛ اما این کُل ماجرا نیست - بیاید کارایی صفحات HTML که قبلا در فلاسک نوشتیم را با Jinja افزایش دهیم. 

همانطور که در برنامه‌نویسی میدانیم و از عنوان پُست پیداست؛ وراثت (Inheritance) اصطلاحی است که در آن فرزند (Child) صفت یا چیزی را از والد (Parent) خود به ارث میبرد. 

شاید در نگاه اول پیاده سازی وراثت در Jinja عجیب بنظر برسد؛ اما بعد از یادگیری خواهید دید که چقدر منطقی و آسان است.

قبل از شروع میخواهم این را روشن سازم؛ در بخش قبل صفحه‌ index.html ساختیم و داخل آن را با تگهای HTML مختلف پُر کردیم - حال این سوال پیش میاید که اگه بخواهیم یک صفحه دیگر مثل about.html داشته باشیم که الگو آن همانند index.html باشد اما محتوایی که بر روی صفحه نمایش میدهد متفاوت باشد چه؟! 


ساخت اُلگو والد

برای این کار لازم است که تغییراتی در ساختار پروژه فلاسک خود داشته باشیم - ما قصد داریم فایل base.html در /templates/dashboard ایجاد کنیم که نقش والد را بازی میکند. قبل از هر چیزی فایل base.html را با HTML زیر پُر کنید تا تغییراتی را که انجام داده‌ایم را توضیح دهم:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{% block title %}{% endblock title %}</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css">
    <link rel="stylesheet" href="{{ url_for('static', filename='styles/styles.css') }}">
    
    {% block styles %}{% endblock styles %}
  </head>
  <body>
    {% block body %}{% endblock body %}

    <script src="{{ url_for('static', filename='scripts/scripts.js') }}"></script>

    {% block scripts %}{% endblock scripts %}
  </body>
</html>


فایل base.html فوق (والد) را طوری تعریف کرده‌ایم که فایل‌های فرزند تمام مشخصات فایل والد را به ارث ببرند - اما سوال اینجاست که والد چه چیزی را به ارث گذاشته است!

اگر به base.html نگاه کنید میبینید که بین تَگ head فایلهای آشنا پیدا میکنید - این همان فایلهای stylesheet است که قبلا تعریف کرده‌اید - اینها همان چیزهایی است که میخواهیم فایل والد ما یعنی base.html برای ارث گذاشتن از خود برای فرزندان داشته باشد، این کار باعث میشود که تمام فایل‌های سی‌اس‌اس، جاوا اسکریپت و ... که بین تَگ head تعریف شده است بین تمام صفحات فرزند (در ادامه خواهیم دید) به اشتراک گذاشته شود و دیگر لازم نیست برای هر فایل HTML فایلهای تکراری سی‌اس‌اس یا جاوا اسکریپت برای لینک شدن داشته باشیم.

شاید در برنامه فلاسک ما لازم باشد در فایل والد شامل فایل‌هایی باشد که در انتهای صفحه بارگذاری شود - بله درست حدس زدید؛ براحتی میتوانید تگهای مورد نیاز را همانند قبل در انتهای تَگ body قرار دهید.

همانطور که شاید حدس زده باشید؛ بیشتر اوقات لازم است هر صفحه‌ی فرزند دارای فایلهای css / javascript خاص خودش باشد. برای این کار در فایل base.html در برخی از بخشها از block استفاده کرده‌ایم. به عنوان مثال هر صفحه (فرزند) میتواند عنوان مجزا داشته باشد:

<title>{% block title %}{% endblock title %}</title>

یا شاید هر صفحه نه تنها میتواند سی‌اس‌اس‌ یا جاوا اسکریپت‌های فایل والد را به ارث ببرد، بلکه علاوه بر این میتواند فایل‌های مجزا خود را دارا باشد!

برای داشتن فایل css بین تَگ head از block استفاده کردیم - نامی که بعد از block آمده است میتواند بدلخواه شما باشد:

{% block styles %}{% endblock styles %}

با این کار ما در فایل والد قسمتی را برای داشتن فایلهای سی‌اس‌اس یا جاوا اسکریپت در صفحات فرزند مشخص کردیم. همین کار را برای فایل‌های javascript انجام دادیم:

{% block scripts %}{% endblock scripts %}

همانطور که شاید درست حدس زده باشید؛ block body جایی است که محتوای هر فایل فرزند در آن محل قرار میگیرد.

در Jinja هر بلاک شروع و پایان خود را دارد که به عنوان مثال با block styles شروع و با endblock styles به اتمام میرسد. 

توجه داشته باشید ایجاد اُلگوهای والد و تُخس کردن آنها بین فرزندان راهی مطمئن و قابل اعتماد برای استفاده مجدد است. 


ساخت اُلگو فرزند

یک اُلگو فرزند تمام صفات اُلگو والد خود را به ارث خواهد برد. اجازه دهید اولین فایل فرزند که index.html است را بصورت زیر بازنویسی کنیم:

{% extends 'dashboard/base.html' %}

{% block title %}
  Dashboard
{% endblock %}

{% block body %} 
  <section class="hero">
    <div class="hero-body">
      <p class="title">
        Welcome to Dashboard
      </p>
    </div>
  </section>
{% endblock body %}

در خط اول از فایل فرزند index.html از دستور extends برای مشخص کردن آدرس فایل والد استفاده کردیم. 

{% extends 'dashboard/base.html' %}

همانطور که قبلا اشاره کردیم عنوان هر صفحه را میتوان مجزا تعیین کرد. عنوانی که میخواهید برای صفحه index.html چاپ شود را بین بلاک block title و endblock title قرار دهید. در مرحله بعد برای داشتن خروجی Welcome to Dashboard همانند بخش قبل تَگهای مورد نظر را بین بلاک body block و endblock body قرار دهید.

اگر دوست داشته باشید فایلهای مجزا جاوا اسکریپت برای فایل index.html داشته باشید میبایست همانند قبل عمل کنید. بله درست حدس زدید:

{% extends 'dashboard/base.html' %}

{% block title %}
  Dashboard
{% endblock %}

{% block body %} 
  <section class="hero">
    <div class="hero-body">
      <p class="title">
        Welcome to Dashboard
      </p>
    </div>
  </section>
{% endblock body %}

{% block scripts %}
  <script>alert("Welcome to Dashboard!");</script>
{% endblock scripts %}

بسیار خوب؛ اگر تا اینجا مراحل فوق را با موفقیت به پایان رسانده‌اید پس حتما قادر خواهید بود تمام مراحل فوق را برای todo انجام دهید، درست همانند صفحه base.html و index.html برای صفحه dashboard.

برای اینکه بیشتر با Jinja احساس راحتی کنید، پیشنهاد میکنم صفحه‌ای را با نام دلخواه about.html برای بخش todo اضافه کنید و تمام مراحل فوق را در آن لحاظ کنید.