Flask Web Development —— Web表單(上)

第二章中介紹的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

一、跨站請求僞造(CSRF)保護

默認狀況下,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類的子類來展示的。該類在表單中定義了一組表單域,每一個都表示爲一個對象。每一個表單域均可以鏈接到一個或多個validatorsvalidators是一個用於檢查用戶提交的輸入是否合法的函數。

示例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渲染的表單

表單域是可調用的,調用時從模板渲染它們到HTML。假設視圖函數傳遞一個參數名爲formNameForm實例給模板,模板就會生成一個簡單的HTML表單,以下所示:

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

固然,結果是什麼都沒有。爲了改變表單的外觀顯示,任何發送給該表單域的參數會被轉換爲HTML表單域屬性;例如,你能夠給定表單域idclass屬性,而後定義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則渲染ifelse之間的內容。若是判斷條件爲False則渲染elseendif之間的內容。示例模板會渲染字符串「Hello, Stranger!」當name模板參數未定義的時候。第二塊內容使用wtf.quick_form()函數渲染NameForm對象。

相關文章
相關標籤/搜索