Flask-WTF擴展使得處理web表單能獲得更愉快的體驗。該擴展是一個封裝了與框架無關的WTForms包的Flask集成。
Flask-WTF和它的依賴集可以通過pip來安裝:
(venv) $ pip install flask-wtf
1、跨站請求偽造(CSRF)保護
默認情況下,Flask-WTF保護各種形式對跨站請求偽造(CSRF)攻擊。一個CSRF攻擊發生在一個惡意網站發送請求給受害者登錄的其他網站。
為了實現CSRF保護,Flask-WTF需要應用程序去配置一個加密密鑰。Flask-WTF使用這個密鑰去生成加密令牌用於驗證請求表單數據的真實性。示例4-1展示如何配置加密密鑰。
示例1. hello.py:Flask-WTF配置
app = Flask(__name__) app.config['SECRET_KEY'] = 'hard to guess string'
app.config
字典通常是框架、擴展或應用程序自身存放配置變量的地方,可以使用標准字典語法添加配置值到app.config
中。配置對象提供方法來從文件或環境導入配置值。
SECRET_KEY
配置變量作為Flask和一些第三方擴展的通用加密密鑰。加密的強度取決於這個變量的值。給你構建的每個應用程序選擇不同的密鑰,並確保這個字符串不被其他任何人知道。
注:為了提高安全性,密鑰應該存儲在一個環境變量中,而不是嵌入到代碼中。這個以后會給出詳細描述。
2、表單類
使用Flask-WTF時,每個web表單是由繼承自Form
類的子類來展現的。該類在表單中定義了一組表單域,每個都表示為一個對象。每個表單域都可以連接到一個或多個validators;validators
是一個用於檢查用戶提交的輸入是否合法的函數。
示例2展示了一個擁有文本框和提交按鈕的簡單web表單。
示例2. hello.py:表單類定義
from flask.ext.wtf import Form from wtforms import StringField, SubmitField from wtforms.validators import Required class NameForm(Form): name = StringField('What is your name?', validators=[Required()]) submit = SubmitField('Submit')
表單中的域被定義為類的變量,且每個類的變量都指定一個表單域類型對象。在上一個示例中,NameForm
表單有一個name
文本框和submit
提交按鈕。StringField
類表示一個type="text"
屬性的<input>
標簽。SubmitField
類表示一個type="submit"
屬性的<input>
標簽。表單域構造函數的第一個參數是一個label
,在渲染表單到HTML時會使用。
StringField
構造函數包含可選參數validators
,它定義了一組檢查來驗證用戶提交的數據。Required()
驗證確保提交的表單域不為空。
注:Flask-WTF擴展定義了表單基類,所以它從flask.ext.wtf導入。表單域、驗證都是直接從WTForms包中導入。
表格4-1展示了一組WTForms支持的標准表單域。
表格4-1. WTForms標准HTML表單域
表格4-2展示了一組WTForms內建驗證。
表格4-2. WTForms驗證
3、HTML渲染的表單
表單域是可調用的,調用時從模板渲染它們到HTML。假設視圖函數傳遞一個參數名為form
的NameForm
實例給模板,模板就會生成一個簡單的HTML表單,如下所示:
<form method="POST"> {{ form.name.label }} {{ form.name() }} {{ form.submit() }} </form>
當然,結果是什么都沒有。為了改變表單的外觀顯示,任何發送給該表單域的參數會被轉換為HTML表單域屬性;例如,你可以給定表單域id
或class
屬性,然后定義CSS樣式:
<form method="POST"> {{ 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樣式渲染它。示例3展示了完整的hello.py
模板。
示例3. 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 %}
目前模板的內容區有兩塊。第一塊是類為page-header
的div輸出一個問候語。這里使用了模板條件判斷語句。在Jinja2中格式為{% if variable %}...{% else %}...{% endif %}
。如果判斷條件為True
則渲染if
和else
之間的內容。如果判斷條件為False
則渲染else
和endif
之間的內容。示例模板會渲染字符串“Hello, Stranger!”當name
模板參數未定義的時候。第二塊內容使用wtf.quick_form()
函數渲染NameForm
對象。