如何在Flask應用程序中使用模板

作者選擇了自由開源基金作為Write for DOnations計劃的一部分進行捐贈。

簡介

Flask是一個輕量級的Python網絡框架,為使用Python語言創建網絡應用程序提供了有用的工具和功能。

在開發網絡應用程序時,將業務邏輯展示邏輯分開是很重要的。業務邏輯是處理用戶請求並與數據庫通信以構建適當響應的部分。展示邏輯是如何將數據呈現給用戶,通常使用HTML文件構建響應網頁的基本結構,並使用CSS樣式來設計HTML組件。例如,在社交媒體應用程序中,您可能有一個用戶名欄位和一個密碼欄位,只有在用戶未登錄時才會顯示。如果用戶已登錄,則顯示登出按鈕。這是展示邏輯。如果用戶輸入了他們的用戶名和密碼,您可以使用Flask執行業務邏輯:從請求中提取數據(用戶名和密碼),如果憑證正確則登錄用戶或回應錯誤信息。錯誤信息的顯示將由展示邏輯處理。

在 Flask 中,您可以使用 Jinja 模板語言來渲染 HTML 模板。模板是一個文件,可以包含固定和動態內容。當用戶從您的應用程序請求某些內容(例如索引頁或登錄頁)時,Jinja 允許您以一個 HTML 模板進行響應,在這個模板中,您可以使用標準 HTML 不具備的許多功能,例如變量、if 語句、for 循環、過濾器和模板繼承。這些功能使您能夠高效地編寫易於維護的 HTML 頁面。Jinja 還會自動進行 HTML 轉義,以防止 跨站腳本攻擊 (XSS)

在本教程中,您將構建一個小型 Web 應用程序,渲染多個 HTML 文件。您將使用變量將數據從服務器傳遞到模板。模板繼承將幫助您避免重複。您將在模板中使用條件和循環等邏輯,使用過濾器修改文本,並使用 Bootstrap 工具包 來設計您的應用程序。

先決條件

步驟 1 — 渲染模板並使用變量

確保你已經激活了你的環境並且已經安裝了 Flask,然後你就可以開始構建你的應用程序了。第一步是在首頁上顯示一條歡迎訪客的消息。你將使用 Flask 的 render_template() 輔助函數來提供一個 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 包中導入了 Flask 類和 render_template() 函數。你使用 Flask 類來創建你的 Flask 應用程序實例,名為 app。然後你定義了一個 視圖函數(這是一個返回 HTTP 響應的 Python 函數),稱為 hello(),使用 app.route() 裝飾器將一個普通函數轉換為視圖函數。這個視圖函數使用 render_template() 函數來渲染一個名為 index.html 的模板文件。

接下來,你需要在flask_app目錄內的templates目錄中創建一個名為index.html的模板文件。Flask會在名為templates模板目錄中尋找模板,因此這個名稱很重要。確保你位於flask_app目錄中,並運行以下命令來創建templates目錄:

  1. mkdir templates

接著,打開templates目錄中的index.html文件進行編輯。這裡的index.html名稱並非標準要求的名稱;你可以將其命名為home.htmlhomepage.html或其他任何名稱:

  1. nano templates/index.html

index.html文件中添加以下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環境變量告訴Flask應用程序的位置(在你的情況下是app.py),並將FLASK_ENV環境變量設置為development,以開發模式運行應用程序並獲得調試器的訪問權限。使用以下命令來完成這些操作(在Windows上,使用set而不是export):

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

然後,使用flask run命令運行應用程序:

  1. flask run

在開發服務器運行的情況下,使用你的瀏覽器訪問以下URL:

http://127.0.0.1:5000/

您會看到頁面的標題設置為 `FlaskApp`,兩個標題是渲染後的 HTML。

在網絡應用程序中,您經常需要將數據從應用程序的 Python 文件傳遞到 HTML 模板。為了演示如何在這個應用程序中實現這一點,您將傳遞一個包含當前 UTC 日期和時間的變量到索引模板,並在模板中顯示該變量的值。

保持服務器運行,並在新終端中打開您的 `app.py` 文件進行編輯:

  1. nano app.py

從 Python 標準庫中導入 `datetime` 模塊,並編輯 `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()`,即當前 UTC 日期和時間。

接下來,要在索引頁面上顯示變量的值,打開 `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/

您將看到類似下圖的頁面:

你已經在 Flask 應用程式中創建了一個包含 HTML 模板的索引頁面,渲染了一個模板,並傳遞和顯示了一個變數值。接下來,你將通過使用模板繼承來避免程式碼重複。

步驟 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`,位於標題區塊內,這樣就替換了 `base.html` 模板中原有的 `title` 區塊,使其文字變為 `Index`,從而完整的標題變成 `Index - FlaskApp`。這樣一來,您可以避免重複相同的文字兩次,因為它既作為頁面的標題,又作為繼承自基礎模板的導航欄下方顯示的標題。

接著還有幾個標題:一個帶有文字 `Hello World!` 的 `<h1>` 標題,一個 `<h2>` 標題,以及一個包含 `utc_dt` 變數值的 `<h3>` 標題。

模板繼承讓您能夠重複使用其他模板(此例中為 `base.html`)中的 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> 標籤。

保存並關閉文件。

在開發服務器運行時,使用瀏覽器訪問以下 URL:

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,當你修改路由時,你的鏈接將會中斷。使用url_for(),你可以編輯路由並保證鏈接仍能正常工作。url_for()函數還會處理其他事情,比如轉義特殊字符。

保存並關閉文件。

現在前往索引頁並嘗試導航欄中的鏈接。你會看到它們如預期般工作。

你學會了如何使用 `url_for()` 函數在模板中連結到其他路由。接下來,你將添加一些條件語句來根據你設定的條件控制模板中顯示的內容,並在模板中使用 `for` 循環來顯示列表項目。

步驟 4 — 使用條件和循環

在這一步中,你將在模板中使用 `if` 語句來根據特定條件控制顯示內容。你還將使用 `for` 循環遍歷 Python 列表並顯示列表中的每個項目。你將添加一個新頁面來顯示評論列表。索引號為偶數的評論將有藍色背景,而索引號為奇數的評論將顯示為灰色背景。

首先,你將為評論頁面創建一個路由。打開你的 `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` 的 Python 列表,其中包含四個項目。(在現實場景中,這些評論通常來自數據庫,而不是像你在這裡硬編碼的那樣。)在最後一行,你返回一個名為 `comments.html` 的模板文件,並將包含列表的變量 `comments` 傳遞給模板文件。

保存並關閉文件。

接下來,在 templates 目錄中打開一個新的 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: #EEE; margin: 20px">
            <p style="font-size: 24px">{{ comment }}</p>
        </div>
        {% endfor %}
    </div>
{% endblock %}

在這裡,您擴展了 base.html 模板並替換了 content 塊的內容。首先,您使用一個 <h1> 標題,同時也作為頁面的標題。

您在 {% for comment in comments %} 這一行中使用 Jinja 的 for 循環來遍歷 comments 列表中的每個評論(這些評論會存儲在 comment 變量中)。您在 <p style="font-size: 24px">{{ comment }}</p> 標籤中顯示評論,就像在 Jinja 中通常顯示變量一樣。您使用 {% endfor %} 關鍵字標記 for 循環的結束。這與 Python 的 for 循環構造不同,因為在 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 loop.index % 2 == 0 %}中添加了一個if語句。loop變數是一個特殊的Jinja變數,它讓你能夠訪問當前循環的資訊。在這裡,你使用loop.index來獲取當前項目的索引,該索引從1開始,而不是像Python列表那樣從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語句進行多種用途,包括控制頁面上顯示的內容。例如,為了顯示除第二條評論外的所有評論,您可以使用條件為loop.index != 2if語句來過濾掉第二條評論。

打開評論模板:

  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()輔助工具以簡化操作,其餘部分未變。您使用{% endif %}結束if語句。

保存並關閉檔案。

刷新評論頁面,您會看到第二條評論未被顯示。

現在,您需要在導航欄中添加一個帶用戶到評論頁面的鏈接。打開基礎模板進行編輯:

  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循環來遍歷Python列表並顯示每個項目,並學習了Jinja中的特殊loop變數。接下來,你將使用Jinja過濾器來控制變數數據的顯示方式。

步驟5 — 使用過濾器

在這一步中,你將學習如何在模板中使用Jinja過濾器。你將使用upper過濾器將前一步中添加的評論轉換為大寫,使用join過濾器將一系列字符串合併為一個字符串,並學習如何使用safe過濾器在不轉義的情況下渲染受信任的HTML代碼。

首先,你將把評論頁面中的評論轉換為大寫。打開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> 標籤,在其中使用 join() 過濾器將 comments 列表中的所有評論連接起來。

保存並關閉文件。

刷新評論頁面,您將看到類似以下的頁面:

如您所見,comments 列表顯示時,評論之間用管道符號分隔,這正是您傳遞給 join() 過濾器的內容。

另一個重要的過濾器是 safe 過濾器,它允許你在瀏覽器上渲染受信任的 HTML。為了說明這一點,你將在評論模板中使用 {{ }} Jinja 分隔符添加一些包含 HTML 標籤的文本。在實際場景中,這將作為變量從服務器傳遞過來。然後你將編輯 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>" 並將 join 參數更改為 <hr> 標籤。

保存並關閉文件。

刷新評論頁面,你會看到類似以下的頁面:

如你所見,HTML 標籤未被渲染。這是 Jinja 的一項安全功能,因為某些 HTML 標籤可能有害,可能導致 跨站腳本 (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 標籤現在按預期渲染:

注意:在處理來自未知數據源的HTML時使用safe過濾器可能會使您的應用程序面臨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>

上述代碼大部分是使用 Bootstrap 所需的樣板代碼。您有一些 meta 標籤,在 <head> 部分有一個指向 Bootstrap CSS 文件的連結,並在底部有一個指向可選 JavaScript 的連結。代碼中高亮的部分包含在前幾步中解釋的 Jinja 代碼。注意您如何使用特定的標籤和 CSS 類來告訴 Bootstrap 如何顯示每個元素。

在上述的 <nav> 標籤中,您有一個帶有 navbar-brand 類的 <a> 標籤,這決定了導航欄中的品牌連結。在 <ul class="navbar-nav"> 標籤內,您在 <li> 標籤中的 <a> 標籤內有常規的導航欄項目。

要了解更多關於這些標籤和 CSS 類的信息,請參閱 Bootstrap 組件

保存並關閉文件。

在開發服務器運行時,使用瀏覽器打開索引頁面:

http://127.0.0.1:5000/

您將看到類似以下的頁面:

現在您可以使用 Bootstrap 組件來在所有模板中為您的 Flask 應用程序中的項目進行樣式設置。

結論

你現在已經知道如何在 Flask 網頁應用程式中使用 HTML 模板。你利用變數將資料從伺服器傳遞到模板,採用模板繼承來避免重複,並整合了如 if 條件式和 for 迴圈等元素,以及在不同頁面間進行連結。你學習了如何使用過濾器來修改文字和顯示受信任的 HTML,並將 Bootstrap 整合進你的應用程式中。

如果你想進一步了解 Flask,可以查看Flask 主題頁面

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