第二章中介紹的request
對象公開了全部客戶端發送的請求信息。特別是request.form
能夠訪問POST
請求提交的表單數據。html
儘管Flask的request
對象提供的支持足以處理web表單,但依然有許多任務會變得單調且重複。表單的HTML代碼生成和驗證提交的表單數據就是兩個很好的例子。git
Flask-WTF擴展使得處理web表單能得到更愉快的體驗。該擴展是一個封裝了與框架無關的WTForms包的Flask集成。github
Flask-WTF和它的依賴集能夠經過pip來安裝:web
(venv) $ pip install flask-wtf
默認狀況下,Flask-WTF保護各類形式對跨站請求僞造(CSRF)攻擊。一個CSRF攻擊發生在一個惡意網站發送請求給受害者登陸的其餘網站。flask
爲了實現CSRF保護,Flask-WTF須要應用程序去配置一個加密密鑰。Flask-WTF使用這個密鑰去生成加密令牌用於驗證請求表單數據的真實性。示例4-1展現如何配置加密密鑰。bootstrap
示例4-1. hello.py:Flask-WTF配置安全
app = Flask(__name__) app.config['SECRET_KEY'] = 'hard to guess string'
app.config
字典一般是框架、擴展或應用程序自身存放配置變量的地方,可使用標準字典語法添加配置值到app.config
中。配置對象提供方法來從文件或環境導入配置值。app
SECRET_KEY
配置變量做爲Flask和一些第三方擴展的通用加密密鑰。加密的強度取決於這個變量的值。給你構建的每一個應用程序選擇不一樣的密鑰,並確保這個字符串不被其餘任何人知道。框架
注:爲了提升安全性,密鑰應該存儲在一個環境變量中,而不是嵌入到代碼中。這個會在第7章中描述。函數
使用Flask-WTF時,每一個web表單是由繼承自Form
類的子類來展示的。該類在表單中定義了一組表單域,每一個都表示爲一個對象。每一個表單域均可以鏈接到一個或多個validators;validators
是一個用於檢查用戶提交的輸入是否合法的函數。
示例4-2展現了一個擁有文本框和提交按鈕的簡單web表單。
示例4-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驗證
表單域是可調用的,調用時從模板渲染它們到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樣式渲染它。示例4-3展現了完整的hello.py
模板。
示例4-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
對象。