قالب ها

شما نماهای احراز هویت را برای برنامه خود نوشته اید، اما اگر سرور را اجرا می کنید و سعی می کنید به هر یک از URL ها بروید، خطای TemplateNotFound را مشاهده خواهید کرد. دلیلش این است که نماها render_template() را فراخوانی می کنند، اما شما هنوز الگوها را ننوشته اید. فایل‌های الگو در دایرکتوری templates در پکیج flaskr ذخیره می‌شوند.

قالب ها فایل هایی هستند که حاوی داده های ثابت و همچنین مکان هایی برای داده های پویا هستند. یک الگو با داده های خاص برای تولید یک سند نهایی ارائه می شود. Flask از کتابخانه الگوی Jinja برای ارائه الگوها استفاده می کند.

در برنامه خود، از الگوهایی برای رندر HTML استفاده خواهید کرد که در مرورگر کاربر نمایش داده می شود. در فلاسک و Jinja برای گریز خودکار هر داده ای که در قالب های HTML ارائه می شود پیکربندی شده است. این بدان معنی است که ارائه ورودی کاربر بی خطر است. هر کاراکتری که وارد کرده‌اند و می‌تواند با HTML به هم بخورد، مانند < و > با مقادیر امن که در مرورگر یکسان به نظر می‌رسند اما اثرات ناخواسته ایجاد نمی‌کنند و حذف می‌شوند.

Jinja بیشتر شبیه پایتون به نظر می رسد و رفتار می کند. جداکننده‌های ویژه برای تشخیص سینتکس Jinja از داده‌های استاتیک در الگو استفاده می‌شوند. هر چیزی بین {{ و }} عبارتی است که به سند نهایی خروجی می‌شود. {% و %} بیانگر یک دستور جریان کنترلی مانند if و for است. بر خلاف پایتون، بلوک‌ها با برچسب‌های شروع و پایان به جای تورفتگی مشخص می‌شوند، زیرا متن استاتیک درون یک بلوک می‌تواند تورفتگی را تغییر دهد.

طرح پایه

هر صفحه در برنامه دارای همان طرح اولیه در اطراف بدنه متفاوتی خواهد بود. به جای نوشتن کل ساختار HTML در هر قالب، هر الگو یک الگوی پایه را بسط می دهد و بخش های خاصی را لغو می کند.

flaskr/templates/base.html
<!doctype html>
<title>{% block title %}{% endblock %} - Flaskr</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav>
  <h1>Flaskr</h1>
  <ul>
    {% if g.user %}
      <li><span>{{ g.user['username'] }}</span>
      <li><a href="{{ url_for('auth.logout') }}">Log Out</a>
    {% else %}
      <li><a href="{{ url_for('auth.register') }}">Register</a>
      <li><a href="{{ url_for('auth.login') }}">Log In</a>
    {% endif %}
  </ul>
</nav>
<section class="content">
  <header>
    {% block header %}{% endblock %}
  </header>
  {% for message in get_flashed_messages() %}
    <div class="flash">{{ message }}</div>
  {% endfor %}
  {% block content %}{% endblock %}
</section>

g به طور خودکار در قالب ها موجود است. بر اساس اینکه g.user تنظیم شده باشد (از load_logged_in_user)، یا نام کاربری و پیوند خروج نمایش داده می شود یا پیوندهایی برای ثبت نام و ورود به سیستم نمایش داده می شود. url_for() نیز به صورت خودکار در دسترس است و به جای نوشتن دستی، برای ایجاد URL برای بازدیدها استفاده می شود.

بعد از عنوان صفحه و قبل از محتوا، الگو روی هر پیامی که توسط get_flashed_messages() برگردانده می شود، حلقه می زند. شما از flash() در نماها برای نمایش پیام های خطا استفاده کردید و این کدی است که آنها را نمایش می دهد.

سه بلوک در اینجا تعریف شده است که در سایر قالب ها لغو می شوند:

  1. {% block title %} عنوان نمایش داده شده در برگه و عنوان پنجره مرورگر را تغییر می دهد.

  2. {% block header %} شبیه به title است اما عنوان نمایش داده شده در صفحه را تغییر می دهد.

  3. {% block content %} جایی است که محتوای هر صفحه مانند فرم ورود به سیستم یا یک پست وبلاگ قرار می گیرد.

الگوی پایه مستقیماً در فهرست templates قرار دارد. برای سازماندهی سایر موارد، الگوهای یک طرح اولیه در فهرستی با همان نام طرح اولیه قرار می گیرند.

ثبت نام

flaskr/templates/auth/register.html
{% extends 'base.html' %}

{% block header %}
  <h1>{% block title %}Register{% endblock %}</h1>
{% endblock %}

{% block content %}
  <form method="post">
    <label for="username">Username</label>
    <input name="username" id="username" required>
    <label for="password">Password</label>
    <input type="password" name="password" id="password" required>
    <input type="submit" value="Register">
  </form>
{% endblock %}

{% extensions 'base.html' %} به Jinja می‌گوید که این الگو باید جایگزین بلوک‌های الگوی پایه شود. تمام محتوای رندر شده باید در برچسب‌های {% block %} که بلوک‌های الگوی پایه را لغو می‌کنند، ظاهر شوند.

یک الگوی مفید استفاده شده در اینجا، قرار دادن {% block title %} در داخل {% block header %} است. این بلوک عنوان را تنظیم می کند و سپس مقدار آن را در بلوک هدر خروجی می دهد، به طوری که پنجره و صفحه بدون دو بار نوشتن عنوان یکسانی را به اشتراک می گذارند.

تگ‌های input از ویژگی required در اینجا استفاده می‌کنند. این به مرورگر می‌گوید تا زمانی که آن فیلدها پر نشده‌اند، فرم را ارسال نکند. اگر کاربر از مرورگر قدیمی‌تری استفاده می‌کند که آن ویژگی را پشتیبانی نمی‌کند، یا اگر از چیزی به غیر از مرورگر برای درخواست‌ها استفاده می‌کند، همچنان می‌خواهید اعتبارسنجی کنید. داده ها در نمای Flask مهم است که همیشه داده های روی سرور را به طور کامل اعتبار سنجی کنید، حتی اگر کلاینت اعتبارسنجی را نیز انجام دهد.

وارد شدن

این با الگوی ثبت نام به جز دکمه عنوان و ارسال یکسان است.

flaskr/templates/auth/login.html
{% extends 'base.html' %}

{% block header %}
  <h1>{% block title %}Log In{% endblock %}</h1>
{% endblock %}

{% block content %}
  <form method="post">
    <label for="username">Username</label>
    <input name="username" id="username" required>
    <label for="password">Password</label>
    <input type="password" name="password" id="password" required>
    <input type="submit" value="Log In">
  </form>
{% endblock %}

ثبت نام کاربر

اکنون که قالب های احراز هویت نوشته شده است، می توانید یک کاربر ثبت نام کنید. مطمئن شوید که سرور همچنان در حال اجراست (اگر اجرا نشده است flask run را بزنید)، سپس به http://127.0.0.1:5000/auth/register بروید.

سعی کنید بدون پر کردن فرم روی دکمه Register کلیک کنید و ببینید که مرورگر یک پیغام خطا نشان می دهد. سعی کنید ویژگی‌های required را از الگوی register.html حذف کنید و دوباره روی Register کلیک کنید. به جای اینکه مرورگر خطا را نشان دهد، صفحه دوباره بارگیری می شود و خطای flash() در نمای نمایش داده می شود.

نام کاربری و رمز عبور را پر کنید و به صفحه ورود هدایت می شوید. سعی کنید یک نام کاربری نادرست یا نام کاربری صحیح و رمز عبور نادرست وارد کنید. اگر وارد سیستم شوید با خطا مواجه می شوید زیرا هنوز نمای index برای تغییر مسیر وجود ندارد.

با فایل های استاتیک ادامه دهید.