五、表單
1、Flask-WTF 擴充套件
Flask-WTF 及其依賴可使用 pip 安裝:
(venv) $ pip install flask-wtf
2、跨站請求偽造保護
【設定金鑰】
app = Flask(__name__)
app.config[`SECRET_KEY`] = `hard to guess string`
app.config 字典可用來儲存框架、 擴充套件和程式本身的配置變數。
3、表單類
建立表單的三個步驟:
-
定義Form的子類
-
在類裡新增欄位
-
在欄位裡新增驗證函式
# Form 基類由 Flask-WTF 擴充套件定義
from flask_wtf import FlaskForm
# 欄位直接從 WTForms 包中匯入
from wtforms import StringField,SubmitField
# 驗證函式直接從 WTForms 包中匯入
from wtforms.validators import DataRequired,Length
class NameForm(Form):
name = StringField(`Input your name:`,validators=[DataRequired()])
submit = SubmitField(`Submit`)
與其他擴充套件的使用方法不同之處在於:
①不是例項化,而是繼承
②還需要從wtforms當中匯入欄位和驗證函式
【注意】
Form 基類由 Flask-WTF 擴充套件定義,所以從 flask_wtf 中匯入。欄位和驗證函式
卻可以直接從 WTForms 包中匯入。
4、把表單渲染成HTML
表單欄位是可呼叫的,在模板中呼叫後會渲染成 HTML。假設檢視函式把一個
NameForm 例項通過引數 form傳入模板,在模板中可以生成一個簡單的表單,
如下所示:
<form method="POST">
{{ form.hidden_tag() }}
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }}
</form>
可以使用Bootstrap 中預先定義好的表單樣式渲染整個 Flask-WTF 表單,
使用 Flask-Bootstrap,上述表單可使用下面的方式渲染:
{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}
具體渲染方式如下:
【form.html】
{% 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 %}
模板的內容區現在有兩部分。第一部分是頁面頭部,顯示歡迎訊息。這裡用到了一個
模板條件語句。 Jinja2中的條件語句格式為 {% if condition %}…{% else %}…{% endif %}。
如果條件的計算結果為 True,那麼渲染 if 和 else 指令之間的值。如果條件的計算結果為False,
則渲染else 和 endif 指令之間的值。在這個例子中,如果沒有定義模板變數 name,則會渲染字
符串“Hello,Stranger!”。內容區的第二部分使用 wtf.quick_form() 函式渲染NameForm 物件。
5、在檢視函式中處理表單
檢視函式 index() 不僅要渲染表單,還要接收表單中的資料。
@app.route(`/form/`,methods = [`GET`,`POST`])
def form():
name = None
form = NameForm()
if form.validate_on_submit():
name = form.name.data
form.name.data = ``
return render_template(`form.html`,form = form, name = name)
6、重定向和使用者會話
上面的檢視函式存在一個可用性問題。使用者輸入名字後提交表單,然後點選瀏覽器
的重新整理按鈕,會看到一個莫名其妙的警告,要求在再次提交表單之前進行確認:
之所以出現這種情況,是因為重新整理頁面時瀏覽器會重新傳送之前已經傳送過的最後
一個請求。如果這個請求是一個包含表單資料的 POST 請求,重新整理頁面後會再次提
交表單。大多數情況下,這並不是理想的處理方式。很多使用者都不理解瀏覽器發出
的這個警告。基於這個原因, 最好別讓 Web 程式把 POST 請求作為瀏覽器傳送的
最後一個請求。
這種需求的實現方式是, 使用**重定向**作為 POST 請求的響應,而不是使用常規
響應。這個技巧稱為 Post/ 重定向 /Get 模式。
程式可以把資料儲存在** 使用者會話 **中,在請求之間“記住”資料。使用者會話是一
種私有儲存,存在於每個連線伺服器的客戶端中。 我們在請求與響應中介紹過使用者
會話,它是請求上下文中的變數,名為 ** session **,像標準的 Python 字典一
樣操作。
from flask import session
@app.route(`/form2/`,methods = [`GET`,`POST`])
def form2():
form = NameForm()
if form.validate_on_submit():
session[`name`] = form.name.data
# 這裡也不需要設定form.name.data = ``,
# 因為已經重定向到別的url去了,下次再到這個介面會自動初始化為``
return redirect(url_for(`hello`))
return render_template(`form.html`,form = form, name = session.get(`name`))
7、Flash訊息
請求完成後,有時需要讓使用者知道狀態發生了變化。這裡可以使用確認訊息、警告或者
錯誤提醒。一個典型例子是,使用者提交了有一項錯誤的登入表單後,伺服器發回的響應
重新渲染了登入表單,並在表單上面顯示一個訊息,提示使用者使用者名稱或密碼錯誤。
通過Flask 的核心特性,** flash()函式 **可實現這種效果
from flask import flash
@app.route(`/form3/`,methods = [`GET`,`POST`])
def form3():
form = NameForm()
if form.validate_on_submit():
old_name = session.get(`name`)
if old_name is not None and old_name != form.name.data :
flash(`you have changed your name`)
session[`name`] = form.name.data
return redirect(url_for(`hello`))
return render_template(`form.html`,form = form, name = session.get(`name`))
僅呼叫 flash() 函式並不能把訊息顯示出來,程式使用的模板要渲染這些訊息。
最好在基模板中渲染 Flash訊息,因為這樣所有頁面都能使用這些訊息。 Flask
把 get_flashed_messages() 函式開放給模板,用來獲取並渲染訊息。
【base.html】
{% block content %}
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ message }}
</div>
{% endfor %}
{% block page_content %}{% endblock %}
</div>
{% endblock %}
在這個示例中,使用 Bootstrap 提供的警報 CSS 樣式渲染警告訊息。
【注意】
在模板中使用迴圈是因為在之前的請求迴圈中每次呼叫 flash() 函式時都會生成一個訊息,
所以可能有多個訊息在排隊等待顯示。 get_flashed_messages() 函式獲取的訊息在下次調
用時不會再次返回,因此 Flash訊息只顯示一次,然後就消失了。