範本

您已經為您的應用程式撰寫了身份驗證視圖,但是如果您正在執行伺服器並嘗試前往任何 URL,您將會看到 TemplateNotFound 錯誤。那是因為視圖正在呼叫 render_template(),但是您尚未撰寫範本。範本檔案將會儲存在 templates 目錄中,該目錄位於 flaskr 套件內。

範本是包含靜態資料以及動態資料預留位置的檔案。範本會使用特定資料進行呈現,以產生最終文件。Flask 使用 Jinja 範本庫來呈現範本。

在您的應用程式中,您將使用範本來呈現 HTML,這將顯示在使用者的瀏覽器中。在 Flask 中,Jinja 被配置為對在 HTML 範本中呈現的任何資料進行自動跳脫。這表示呈現使用者輸入是安全的;他們輸入的任何可能搞亂 HTML 的字元,例如 <>,都將會使用安全值進行跳脫,這些安全值在瀏覽器中看起來相同,但不會造成不必要的影響。

Jinja 的外觀和行為大多與 Python 相似。特殊的定界符用於區分 Jinja 語法與範本中的靜態資料。在 {{}} 之間的任何內容都是將輸出到最終文件的表達式。{%%} 表示控制流程語句,例如 iffor。與 Python 不同,區塊由開始和結束標籤而不是縮排表示,因為區塊內的靜態文字可能會更改縮排。

基礎佈局

應用程式中的每個頁面都將在不同的主體周圍具有相同的基本佈局。每個範本將擴展基礎範本並覆寫特定區段,而不是在每個範本中編寫完整的 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 %}

{% extends '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.html 範本中移除 required 屬性,然後再次點擊「註冊」。頁面將重新載入,並且會顯示視圖中 flash() 產生的錯誤,而不是瀏覽器顯示錯誤。

填寫使用者名稱和密碼,您將被重新導向到登入頁面。嘗試輸入不正確的使用者名稱,或正確的使用者名稱和不正確的密碼。如果您登入,您將會收到錯誤,因為還沒有 index 視圖可以重新導向。

繼續前往 靜態檔案