04.flask表單


配套視頻教程

本文B站配套視頻教程

Flask-WTF 擴展可以把處理 Web 表單的過程變成一種愉悅的體驗。這個擴展對獨立的 WTForms 包進行了包裝,方便集成到 Flask 應用中。

Flask-WTF 及其依賴可使用 pip 安裝:

pip install flask-wtf

配置

與其他多數擴展不同,Flask-WTF 無須在應用層初始化,但是它要求應用配置一個密鑰。密鑰是一個由隨機字符構成的唯一字符串,通過加密或簽名以不同的方式提升應用的安全性。Flask 使用這個密鑰保護用戶會話,以防被篡改。

hello.py

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

app.config 字典可用於存儲 Flask、擴展和應用自身的配置變量。使用標准的字典句法就能把配置添加到 app.config 對象中。這個對象還提供了一些方法,可以從文件或環境中導入配置。

Flask-WTF 之所以要求應用配置一個密鑰,是為了防止表單遭到跨站請求偽造(CSRF,cross-site request forgery)攻擊。惡意網站把請求發送到被攻擊者已登錄的其他網站時,就會引發 CSRF 攻擊。Flask-WTF 為所有表單生成安全令牌,存儲在用戶會話中。

表單類

使用 Flask-WTF 時,在服務器端,每個 Web 表單都由一個繼承自 FlaskForm 的類表示。這個類定義表單中的一組字段,每個字段都用對象表示。字段對象可附屬一個或多個驗證函數。驗證函數用於驗證用戶提交的數據是否有效。

示例是一個簡單的 Web 表單,包含一個文本字段和一個提交按鈕。

hello.py

from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

class NameForm(FlaskForm):
    name = StringField('What is your name?', validators=[DataRequired()])
    submit = SubmitField('Submit')

這個表單中的字段都定義為類變量,而各個類變量的值是相應字段類型的對象。在這個示例中,NameForm 表單中有一個名為 name 的文本字段和一個名為 submit 的提交按鈕。StringField 類表示屬性為 type="text" 的 HTML <input> 元素。SubmitField 類表示屬性為 type="submit" 的 HTML <input> 元素。字段構造函數的第一個參數是把表單渲染成 HTML 時使用的標注(label)。

StringField 構造函數中的可選參數 validators 指定一個由驗證函數組成的列表,在接受用戶提交的數據之前驗證數據。驗證函數 DataRequired() 確保提交的字段內容不為空。

FlaskForm 基類由 Flask-WTF 擴展定義,所以要從 flask_wtf 中導入。然而,字段和驗證函數卻是直接從 WTForms 包中導入的。

WTForms 支持的 HTML 標准字段如表所示。

表:WTForms支持的HTML標准字段

字段類型 說明
BooleanField 復選框,值為 TrueFalse
DateField 文本字段,值為 datetime.date 格式
DateTimeField 文本字段,值為 datetime.datetime 格式
DecimalField 文本字段,值為 decimal.Decimal
FileField 文件上傳字段
HiddenField 隱藏的文本字段
MultipleFileField 多文件上傳字段
FieldList 一組指定類型的字段
FloatField 文本字段,值為浮點數
FormField 把一個表單作為字段嵌入另一個表單
IntegerField 文本字段,值為整數
PasswordField 密碼文本字段
RadioField 一組單選按鈕
SelectField 下拉列表
SelectMultipleField 下拉列表,可選擇多個值
SubmitField 表單提交按鈕
StringField 文本字段
TextAreaField 多行文本字段

WTForms 內建的驗證函數如表所示。

表:WTForms驗證函數

驗證函數 說明
DataRequired 確保轉換類型后字段中有數據
Email 驗證電子郵件地址
EqualTo 比較兩個字段的值;常用於要求輸入兩次密碼進行確認的情況
InputRequired 確保轉換類型前字段中有數據
IPAddress 驗證 IPv4 網絡地址
Length 驗證輸入字符串的長度
MacAddress 驗證 MAC 地址
NumberRange 驗證輸入的值在數字范圍之內
Optional 允許字段中沒有輸入,將跳過其他驗證函數
Regexp 使用正則表達式驗證輸入值
URL 驗證 URL
UUID 驗證 UUID
AnyOf 確保輸入值在一組可能的值中
NoneOf 確保輸入值不在一組可能的值中

把表單渲染成HTML

表單字段是可調用的,在模板中調用后會渲染成 HTML。假設視圖函數通過 form 參數把一個 NameForm 實例傳入模板,在模板中可以生成一個簡單的 HTML 表單,如下所示:

<form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name() }}
    {{ form.submit() }}
</form>

注意,除了 namesubmit 字段,這個表單還有個 form.hidden_tag() 元素。這個元素生成一個隱藏的字段,供 Flask-WTF 的 CSRF 防護機制使用。

當然,這種方式渲染出的表單還很簡陋。調用字段時傳入的任何關鍵字參數都將轉換成字段的 HTML 屬性。例如,可以為字段指定 idclass 屬性,然后為其定義 CSS 樣式:

<form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name(id='my-text-field') }}
    {{ form.submit() }}
</form>

即便能指定 HTML 屬性,但按照這種方式渲染及美化表單的工作量還是很大,所以在條件允許的情況下,最好使用 Bootstrap 的表單樣式。Flask-Bootstrap 擴展提供了一個高層級的輔助函數,可以使用 Bootstrap 預定義的表單樣式渲染整個 Flask-WTF 表單,而這些操作只需一次調用即可完成。使用 Flask-Bootstrap,上述表單可以用下面的方式渲染:

{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}

import 指令的使用方法和普通 Python 代碼一樣,通過它可以導入模板元素,在多個模板中使用。導入的 bootstrap/wtf.html 文件中定義了一個使用 Bootstrap 渲染 Flask-WTF 表單對象的輔助函數。wtf.quick_form() 函數的參數為 Flask-WTF 表單對象,使用 Bootstrap 的默認樣式渲染傳入的表單。hello.py 的完整模板如示例所示。

示例 templates/index.html:使用 Flask-WTF 和 Flask-Bootstrap 渲染表單

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}Flasky{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>
{{ wtf.quick_form(form) }}
{% endblock %}

base.html

{% extends "bootstrap/base.html" %}

{% block title %}Flasky{% endblock %}

{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle"
             data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class="container">
    {% block page_content %}{% endblock %}
</div>
{% endblock %}

在視圖函數中處理表單

在新版 hello.py 中,視圖函數 index() 有兩個任務:一是渲染表單,二是接收用戶在表單中填寫的數據。以下示例是更新后的 index() 視圖函數。

示例 hello.py:使用 GETPOST 請求方法處理 Web 表單

@app.route('/', methods=['GET', 'POST'])
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data
        form.name.data = ''
    return render_template('index.html', form=form, name=name)

app.route 裝飾器中多出的 methods 參數告訴 Flask,在 URL 映射中把這個視圖函數注冊為 GETPOST 請求的處理程序。如果沒指定 methods 參數,則只把視圖函數注冊為 GET 請求的處理程序。

這里有必要把 POST 加入方法列表,因為更常使用 POST 請求處理表單提交。表單也可以通過 GET 請求提交,但是 GET 請求沒有主體,提交的數據以查詢字符串的形式附加到 URL 中,在瀏覽器的地址欄中可見。基於這個以及其他多個原因,處理表單提交幾乎都使用 POST 請求。

圖1 是用戶首次訪問網站時瀏覽器顯示的表單。用戶提交名字后,應用會生成一個針對該用戶的歡迎消息。歡迎消息下方還是會顯示這個表單,以便用戶輸入新名字。圖 2 顯示了此時應用的樣子。

image.png

圖1:Flask-WTF Web 表單

image.png

圖2:提交后顯示的 Web 表單

如果用戶提交表單之前沒有輸入名字,那么 DataRequired() 驗證函數會捕獲這個錯誤,如圖3 所示。注意這個擴展自動提供了多少功能。這說明,像 Flask-WTF 和 Flask-Bootstrap 這樣設計良好的擴展能給應用提供十分強大的功能。

image.png

圖3:驗證失敗后顯示的 Web 表單


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM