如何在Flask應用程序中使用Web表單

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

引言

網頁表單,例如文字欄位和文字區域,允許使用者向您的應用程式發送數據,以便執行某個動作,或向應用程式發送更大的文字區域。例如,在社交媒體應用程式中,您可能會提供一個方塊,讓使用者可以添加新內容到他們的頁面。另一個例子是登錄頁面,您會提供一個文字欄位供使用者輸入用戶名,以及一個密碼欄位供他們輸入密碼。伺服器(在此情況下是您的Flask應用程式)會使用使用者提交的數據,如果數據有效,則會登錄他們;如果數據不正確,則會回應類似無效憑證!的訊息,告知使用者他們提交的數據不正確。

Flask 是一個輕量級的 Python 網頁框架,為使用 Python 語言創建網頁應用程式提供了有用的工具和功能。在本教程中,您將構建一個小型網頁應用程式,展示如何使用網頁表單。該應用程式將有一個頁面用於顯示存儲在 Python 列表中的消息,以及一個頁面用於添加新消息。您還將使用 消息閃現 來告知用戶在提交無效數據時的錯誤。

先決條件

第一步 — 顯示訊息

在這一步中,您將創建一個Flask應用程式,其主頁用於顯示存儲在Python字典列表中的訊息。

首先,打開一個名為app.py的新文件進行編輯:

  1. nano app.py

app.py文件中添加以下程式碼,以創建一個帶有單一路由的Flask伺服器:

flask_app/app.py
from flask import Flask, render_template

app = Flask(__name__)

messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]

@app.route('/')
def index():
    return render_template('index.html', messages=messages)

保存並關閉文件。

在這個文件中,您首先從flask套件導入了Flask類和render_template()函數。然後使用Flask類創建了一個新的應用程式實例,稱為app,並傳遞了特殊的__name__變量,這是Flask在幕後設置一些路徑所必需的。模板渲染在教程如何在Flask應用程式中使用模板中有所介紹。

接著創建了一個名為messages的全局Python列表,其中包含Python字典。每個字典有兩個鍵:title用於訊息標題,content用於訊息內容。這是一個簡化的數據存儲方法示例;在實際應用中,您會使用一個能永久保存數據並允許更高效操作的數據庫。

在建立 Python 列表後,您使用 @app.route() 裝飾器來創建一個名為 index()視圖函數。在其中,您返回對 render_template() 函數的調用,這指示 Flask 該路由應顯示一個 HTML 模板。您將此模板命名為 index.html(稍後將創建它),並向其傳遞一個名為 messages 的變量。該變量保存了您先前聲明的 messages 列表作為值,並使其可被 HTML 模板訪問。視圖函數在教程《如何使用 Flask 和 Python 3 創建您的首個 Web 應用》中有詳細介紹。

接下來,在您的 flask_app 目錄中創建一個 templates 文件夾,Flask 會在其中搜索模板,然後打開一個名為 base.html 的模板文件,該文件將包含其他模板繼承以避免代碼重複的代碼:

  1. mkdir templates
  2. 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>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

保存並關閉文件。

這個基礎模板包含了所有你會在其他模板中重複使用的HTML樣板。title區塊將被替換以設定每個頁面的標題,而content區塊將被替換為每個頁面的內容。導覽列有兩個連結,一個是索引頁,你使用url_for()輔助函數來連結到index()視圖函數,另一個是關於頁面,如果你選擇在應用程式中包含一個。

接下來,打開一個名為index.html的模板。這是你參考在app.py文件中的模板:

  1. nano templates/index.html

將以下代碼添加到其中:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Messages {% endblock %}</h1>
    {% for message in messages %}
        <div class='message'>
            <h3>{{ message['title'] }}</h3>
            <p>{{ message['content'] }}</p>
        </div>
    {% endfor %}
{% endblock %}

保存並關閉文件。

在這段代碼中,你擴展了base.html模板並替換了content區塊的內容。你使用了一個<h1>標題,同時也作為標題。

你在{% for message in messages %}這一行中使用了Jinja for循環來遍歷messages列表中的每個消息。你使用了一個<div>標籤來包含消息的標題和內容。你將標題顯示在<h3>標題中,而內容則顯示在<p>標籤中。

當你在激活了虛擬環境的flask_app目錄中時,使用FLASK_APP環境變數告訴Flask關於應用程式(在此例中是app.py)的信息:

  1. export FLASK_APP=app

接著,將 FLASK_ENV 環境變數設定為 development,以開發模式運行應用程式並啟用調試器。更多關於 Flask 調試器的資訊,請參閱 如何在 Flask 應用程式中處理錯誤。使用以下命令進行設定(在 Windows 上,使用 set 而非 export):

  1. export FLASK_ENV=development

接下來,運行應用程式:

  1. flask run

開發伺服器運行後,使用瀏覽器訪問以下 URL:

http://127.0.0.1:5000/

你將在首頁上看到 messages 列表中的訊息:

現在你已經設置了網頁應用程式並顯示了訊息,接下來需要一種方法讓用戶能在首頁添加新訊息。這可以透過網頁表單來實現,你將在下一步中設置。

步驟 2 — 設置表單

在這一步中,你將創建一個頁面,允許用戶透過網頁表單向訊息列表添加新訊息。

保持開發伺服器運行,並打開一個新的終端窗口。

首先,打開你的 app.py 文件:

  1. nano app.py

在文件末尾添加以下路由:

flask_app/app.py
# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

保存並關閉文件。

這個 /create 路由具有 methods 參數,其值為元組 ('GET', 'POST'),用於接受 GETPOST 請求。GETPOSTHTTP 方法。默認情況下,只接受 GET 請求,這些請求用於檢索數據,例如向服務器請求索引頁或關於頁。POST 請求則用於向特定路由提交數據,這通常會改變服務器上的數據。

在此示例中,您將使用 GET 請求來請求 create 頁面。Create 頁面將包含一個帶有輸入字段和提交按鈕的網頁表單。當用戶填寫網頁表單並點擊提交按鈕時,會向 /create 路由發送一個 POST 請求。在那裡處理請求,驗證提交的數據以確保用戶未提交空表單,並將其添加到 messages 列表中。

目前,create() 視圖函數僅做一件事:當接收到常規的 GET 請求時,渲染一個名為 create.html 的模板。您現在將創建此模板,然後在下一步中編輯該函數以處理 POST 請求。

打開一個新的模板文件,名為 create.html

  1. nano templates/create.html

向其中添加以下代碼:

flask_app/templates/create.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Add a New Message {% endblock %}</h1>
    <form method="post">
        <label for="title">Title</label>
        <br>
        <input type="text" name="title"
               placeholder="Message title"
               value="{{ request.form['title'] }}"></input>
        <br>

        <label for="content">Message Content</label>
        <br>
        <textarea name="content"
                  placeholder="Message content"
                  rows="15"
                  cols="60"
                  >{{ request.form['content'] }}</textarea>
        <br>
        <button type="submit">Submit</button>
    </form>
{% endblock %}

保存並關閉文件。

在這段程式碼中,您擴展了 `base.html` 模板,並將 `content` 區塊替換為一個 `<h1>` 標題,作為頁面的標題。在 `<form>` 標籤中,您將 `method` 屬性設置為 `post`,以便表單數據以 `POST` 請求的形式發送到伺服器。

在表單中,您有一個名為 `title` 的文字輸入欄位;這是您將在應用程式中用於訪問標題表單數據的名稱。您為 `<input>` 標籤設置了一個 `value` 為 `{{ request.form['title'] }}`。這在恢復用戶輸入的數據時非常有用,以免在出現問題時丟失數據。例如,如果用戶忘記填寫必需的 `content` 文字區域,請求將發送到伺服器,並且錯誤消息將作為響應返回,但標題中的數據不會丟失,因為它將保存在 `request` 全局對象中,並且可以通過 `request.form['title']` 訪問。

在標題輸入欄位之後,您添加了一個名為 `content` 的文字區域,其值為 `{{ request.form['content'] }}`,原因與前面提到的相同。

最後,您在表單末尾添加了一個提交按鈕。

現在,在開發伺服器運行時,使用您的瀏覽器導航到 `/create` 路由:

http://127.0.0.1:5000/create

您將看到一個“添加新消息”頁面,其中包含一個消息標題的輸入欄位、一個消息內容的文字區域和一個提交按鈕。

此表單向您的 create() 視圖函數提交一個 POST 請求。然而,該函數中尚未有處理 POST 請求的代碼,因此在填寫表單並提交後不會發生任何事情。在下一步中,您將處理表單提交時的傳入 POST 請求。您將檢查提交的數據是否有效(非空),並將消息標題和內容添加到 messages 列表中。

步驟 3 — 處理表單請求

在此步驟中,您將在應用端處理表單請求。您將通過前一步創建的表單訪問用戶提交的數據,並將其添加到消息列表中。您還將使用 消息閃現 來通知用戶在提交無效數據時的情況。閃現消息 僅顯示一次,並且在下一個請求時消失(例如,如果您導航到另一個頁面)。

打開 app.py 文件進行編輯:

  1. nano app.py

首先,您將從 Flask 框架導入以下內容:

  • 全局 request 對象,用於訪問將通過上一步構建的 HTML 表單提交的傳入請求數據。
  • url_for() 函數用於生成 URL。
  • 使用 flash() 函數在處理請求時顯示消息(告知用戶一切順利,或在提交的數據無效時通知他們問題所在)。
  • 使用 redirect() 函數將客戶端重定向到其他位置。

將這些導入添加到文件的第一行:

flask_app/app.py
from flask import Flask, render_template, request, url_for, flash, redirect

# ...

flash() 函數將閃現消息存儲在客戶端瀏覽器會話中,這需要設置一個 密鑰。此密鑰用於保護會話,使 Flask 能夠記住從一次請求到另一次請求的信息,例如從新消息頁面移動到索引頁面。用戶可以訪問存儲在會話中的信息,但除非他們擁有密鑰,否則無法修改它,因此您絕不能允許任何人訪問您的密鑰。更多信息請參閱 Flask 文檔中的會話部分

密鑰應為一串長的隨機字符串。您可以使用 os 模組中的 os.urandom() 方法生成密鑰,該方法返回一串適合加密用途的隨機字節。要使用它獲取隨機字符串,請打開一個新的終端並使用以下命令打開 Python 交互式 shell:

  1. python

在 Python 交互式 shell 中,從標準庫導入 os 模組並如下調用 os.urandom() 方法:

  1. import os
  2. os.urandom(24).hex()

您將獲得類似以下字符串:

Output
'df0331cefc6c2b9a5d0208a726a5d1c0fd37324feba25506'

您可以使用獲得的字符串作為您的密鑰。

要設置密鑰,通過 app.config 對象向您的應用程序添加一個 SECRET_KEY 配置。在定義 messages 變量之前,直接在 app 定義後添加它:

flask_app/app.py

# ...
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'


messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]
# ...

接下來,修改 create() 視圖函數,使其完全如下所示:

flask_app/app.py
# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        elif not content:
            flash('Content is required!')
        else:
            messages.append({'title': title, 'content': content})
            return redirect(url_for('index'))

    return render_template('create.html')

if 語句中,您確保只有在請求是 POST 請求時(通過比較 request.method == 'POST'),後續代碼才會執行。

接著,從request.form物件中提取提交的標題和內容,該物件讓您能夠訪問請求中的表單數據。如果未提供標題,條件if not title將被滿足。在這種情況下,您將使用flash()函數向用戶顯示一條消息,告知他們標題是必需的。這將消息添加到閃現消息列表中。稍後,您將在base.html模板中顯示這些消息。同樣地,如果未提供內容,條件elif not content將被滿足。如果是這樣,您將'Content is required!'消息添加到閃現消息列表中。

如果標題和消息內容正確提交,您將使用messages.append({'title': title, 'content': content})行將一個新的字典添加到messages列表中,包含用戶提供的標題和內容。然後,您使用redirect()函數將用戶重定向到索引頁。您使用url_for()函數來鏈接到索引頁。

保存並關閉文件。

現在,使用您的網頁瀏覽器導航到/create路由:

http://127.0.0.1:5000/create

在表單中填寫您選擇的標題和一些內容。提交表單後,您將在索引頁上看到新消息的列表。

最後,您將在base.html模板中顯示閃現消息,並在導航欄中添加“新消息”頁面的鏈接,以便輕鬆訪問此新頁面。打開基礎模板文件:

  1. nano templates/base.html

編輯檔案,在導航欄中的 FlaskApp 連結後面新增一個新的 `<a>` 標籤。然後在 `<nav>` 標籤內部,直接在內容區塊上方新增一個新的 `for` 循環,用於顯示導航欄下方的閃現訊息。這些訊息可通過 Flask 提供的特殊函數 `get_flashed_messages()` 獲取。接著,為每條訊息添加一個名為 `alert` 的類別屬性,並在 `<style>` 標籤內為其設定一些 CSS 屬性:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

        .alert {
            padding: 20px;
            margin: 5px;
            color: #970020;
            background-color: #ffd5de;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% for message in get_flashed_messages() %}
            <div class="alert">{{ message }}</div>
        {% endfor %}
        {% block content %} {% endblock %}
    </div>
</body>
</html>

保存並關閉檔案,然後在瀏覽器中重新載入 `https://127.0.0.1:5000`。導航欄現在將有一個指向 `/create` 路由的“創建”項目。

要查看閃現訊息的工作原理,請前往“創建”頁面,點擊提交按鈕而不填寫兩個欄位。您將收到一條類似以下的訊息:

返回首頁,您會發現導航欄下方的閃現訊息消失了,儘管它們是作為基礎模板的一部分顯示的。如果不是閃現訊息,它們也會在首頁上顯示,因為首頁也繼承自基礎模板。

嘗試提交一個只有標題但沒有內容的表單。你會看到訊息“內容是必需的!”。點擊導覽列中的 FlaskApp 連結返回索引頁,然後點擊返回按鈕回到創建頁面。你會發現訊息內容仍然存在。這只有在點擊返回按鈕時才有效,因為它保存了之前的請求。點擊導覽列中的創建連結會發送一個新請求,這會清除表單,因此閃現訊息將會消失。

現在你已經知道如何接收用戶輸入,如何驗證它,以及如何將其添加到數據源中。

注意:
你添加到 messages 列表中的訊息在伺服器停止時會消失,因為 Python 列表僅保存在記憶體中,要永久保存你的訊息,你需要使用像 SQLite 這樣的數據庫。查看如何在 Python 3 中使用 sqlite3 模組以學習如何使用 SQLite 和 Python。

結論

你創建了一個 Flask 應用程式,用戶可以在索引頁上顯示的訊息列表中添加訊息。你創建了一個網頁表單,處理了用戶透過表單提交的數據,並將其添加到你的訊息列表中。你還使用了閃現訊息來通知用戶在提交無效數據時的情況。

若您想深入瞭解 Flask,請參閱Flask系列中的其他教程

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