4 表單
表單是和用戶交互最常見的方式之一,本章涉及的Python包由WTForms、Flask-WTF、Flask-CKEditor。(p104)
4.1 HTML表單
通過<form>
標(biāo)簽創(chuàng)建表單,<input>
標(biāo)簽創(chuàng)建字段。
<form method="post">
<input type="text" name="username" placeholder="用戶名">
</form>
WTForms:支持在Python中使用類定義表單,然后通過類定義生成對應(yīng)的HTML代碼。
4.2 使用Flask-WTF
Flask-WTF在Flask中集成了表單數(shù)據(jù)解析、CSRF保護(hù)、文件上傳等功能。
# 設(shè)置密鑰,flask-wtf使用程序密鑰來對csrf令牌進(jìn)行簽名(?)
app.secret_key = 'secret string'
定義表單類:
from wtforms import From
class LoginForm(Form):
...
- 常用的WTForms字段、實(shí)例化字段常用參數(shù)、常用的WTForms驗(yàn)證器,見(p107)。
輸出HTML代碼:
>>> form = LoginForm()
>>> form.username() # 假設(shè)在類中定義了username字段
>>> form.username.label()
-
添加額外屬性:輸出的字段HTML代碼默認(rèn)只包含
id
和name
屬性,其他屬性可以:- 1、使用render_kw屬性(p109)
- 2、在調(diào)用時(shí)傳入
在模板中渲染表單:我們需要把表單類實(shí)例傳入模板,然后再模板中調(diào)用表單類的屬性即可獲取字段對應(yīng)的HTML代碼。
return render_template('basic.html', form=form)
<form method="post">
{{ form.csrf_token }}
{{ form.username.label }}
{{ form.username(class='form-contorl') }} <!-- 調(diào)用時(shí)傳入額外屬性值 -->
</form>
-
CSRF字段:在提交表單后會自動驗(yàn)證該字段,為使驗(yàn)證通過,需渲染。
-
可以手動編寫HTML表單的代碼,name屬性與表單類保持一致。
4.3 處理表單數(shù)據(jù)
1 過程:解析請求 --> 轉(zhuǎn)換為Python數(shù)據(jù)類型 --> 驗(yàn)證 --> 處理。
2 提交表單:在HTML中,當(dāng)<form>
標(biāo)簽聲明的表單中類型為submit的提交字段被點(diǎn)擊時(shí),就會創(chuàng)建一個(gè)提交表單的HTTP請求。
HTML表單中控制提交行為的屬性:action(目標(biāo)URL),method(HTTP請求方法),enctype(表單數(shù)據(jù)編碼類型)。(p112)
3 驗(yàn)證表單數(shù)據(jù):
- 客戶端驗(yàn)證:可以實(shí)時(shí)動態(tài)提示用戶的輸入是否正確,降低服務(wù)器負(fù)載。可以通過HTML5內(nèi)置的驗(yàn)證屬性,或Javascript實(shí)現(xiàn)。
- 服務(wù)器端驗(yàn)證:必須的,因?yàn)榭蛻舳瞬豢煽俊?/li>
<!-- 使用html5屬性 -->
<input type="text" name=username" required>
-
WTForms驗(yàn)證機(jī)制:實(shí)例化表單類時(shí)傳入數(shù)據(jù),然后調(diào)用實(shí)例的
validate()
方法,錯(cuò)誤消息會存儲到實(shí)例的errors
屬性對應(yīng)的字典中。
>>> form.errors # 錯(cuò)誤消息字典
- 獲取數(shù)據(jù):data屬性是一個(gè)匹配所有字段與對應(yīng)數(shù)據(jù)的字典。
>>> form.username.data
- PRG模式:(Post/Redirect/Get),在瀏覽器中,刷新頁面時(shí)的默認(rèn)行為是發(fā)送上一個(gè)請求,會導(dǎo)致重復(fù)提交表單。因此在處理表單后應(yīng)返回一個(gè)重定向響應(yīng)(GET)。
4 渲染錯(cuò)誤消息:WTForms會把錯(cuò)誤消息添加到表單類的errors
屬性中,這是一個(gè)匹配作為表單字段的類屬性到對應(yīng)的錯(cuò)誤消息列表的字典。
>>> form.username.errors
4.4 表單進(jìn)階實(shí)踐
簡化表單處理過程的技巧,以及表單的一些非常規(guī)應(yīng)用。
1 設(shè)置錯(cuò)誤消息語言:如下,所有繼承MyBaseForm
的表單類,將使用新設(shè)置的錯(cuò)誤消息默認(rèn)語言。
from flask_wtf import FlaskForm
app = Flask(__name__)
app.config['WTF_I18N_ENABLED'] = False
class MyBaseForm(FlaskForm):
class Meta:
locals = ['zh']
class HelloFrom(MyBaseForm):
...
疑惑:類內(nèi)部再定義一個(gè)Meta類是什么操作?
2 使用宏渲染表單:在模板中渲染表單時(shí),存在大量的重復(fù)工作:獲取<input>
定義、獲取<label>
定義、渲染錯(cuò)誤消息。為了避免每一個(gè)字段重復(fù)這些代碼,可以創(chuàng)建一個(gè)宏。(p120)
{% macro form_field(field) %}
{{ field.label}}<br>
{{ field(**kwargs) }}<br>
{% if field.errors %}
{% for error in field.errors %}
{{ error }}
{% endfor %}
{% endif %}
{% end macro %}
3 自定義驗(yàn)證器:驗(yàn)證器是指在定義字段時(shí)傳入validators參數(shù)列表的可調(diào)用對象,接受form
和field
(字段)兩個(gè)位置參數(shù)。(p121)
- 行內(nèi)驗(yàn)證器:在表單類中定義,用來驗(yàn)證某個(gè)特定的字段。
-
全局驗(yàn)證器:可重用。定義一個(gè)函數(shù),在驗(yàn)證不通過時(shí)拋出
ValidateionError
異常。若需支持參數(shù),可用工廠函數(shù)形式。
工廠函數(shù):返回一個(gè)可調(diào)用對象的函數(shù)。
4 文件上傳:
-
渲染字段:在HTML中,渲染一個(gè)文件上傳字段只需要將
<input
字段的type
屬性值設(shè)置為file。
<input type="file">
可以使用Flask-WTF提供的FileField
類創(chuàng)建文件上傳字段,驗(yàn)證器包括FileRequired
(是否包含文件對象)和FileAllowed
(驗(yàn)證文件類型)。此外,可以通過限制請求報(bào)文的最大長度來限制文件大?。?/p>
app.config['MAX_CONTENT_LENGTH'] = 3 * 1024 * 1024
- 獲取文件:可以在request.files中獲取,解析為Werkzeug中的FileStorage對象。不過Flask-WTF會自動獲取
request.files.get('photo')
# 在Flask-WTF中
f = form.photo.data
- 處理文件名:可以過濾文件名中的危險(xiǎn)字符,或統(tǒng)一重命名(使用uuid)。
- 其它:還有保存文件、獲取保存后的文件、多文件上傳等問題,此處省略,用到的時(shí)候再細(xì)看吧!
疑惑:使用uuid重命名了文件,后續(xù)如何找到這個(gè)文件呢,將文件名保存到數(shù)據(jù)庫?(畢竟文件名是隨機(jī)生成的)
多文件:單擊一次按鈕,可以一次性選擇多個(gè)文件并上傳。
心得筆記:感覺文件上傳這一塊彎彎繞繞挺多的,一時(shí)間看得有點(diǎn)懵。
5 使用Flask-CKEditor集成富文本編輯器:對我也是一個(gè)黑盒子 的感覺(p129)
疑惑:文本應(yīng)該以什么形式保存?
6 單個(gè)表單多個(gè)提交按鈕:
如“發(fā)布文章”和“保存草稿”,需根據(jù)按鈕做出不同的處理??稍诒韱晤悇?chuàng)建多個(gè)SubmitField
類型的字段,只有被點(diǎn)擊的字段才會出現(xiàn)在reqeust.form
字典中,而調(diào)用data
屬性時(shí)則會被處理為True
或False
。
if form.validata_on_submit():
if form.save.data:
...
if form.publish.data:
...
7 單個(gè)頁面多個(gè)表單:
問題是判斷當(dāng)前被提交的是哪個(gè)表單。
- 單視圖處理:為兩個(gè)表單的提交字段設(shè)置不同的名稱。
- 多視圖處理:通常在一個(gè)處理表單的視圖函數(shù)內(nèi)包含了兩類工作:渲染(GET)、處理提交的表單(POST)。因此可以單獨(dú)創(chuàng)建一個(gè)渲染的視圖函數(shù),再為兩個(gè)表單分別創(chuàng)建提交的視圖函數(shù)。
注:表單提交請求的目標(biāo)URL通過
action
屬性設(shè)置。
小記
表單這一節(jié)的內(nèi)容比較豐富、繁雜,涉及的調(diào)包操作也較多,看完后仍有不少細(xì)節(jié)之處理解模糊。偶爾會體會到,之前看過的《Python工匠》對于我理解本書內(nèi)容的幫助。文章來源:http://www.zghlxwxcb.cn/news/detail-675563.html
學(xué)這節(jié)的時(shí)候,我看得多,動手少,難免看了后面忘前面。一節(jié)書看完,再去看相關(guān)的源代碼時(shí)卻仍有些看不懂。文章來源地址http://www.zghlxwxcb.cn/news/detail-675563.html
到了這里,關(guān)于Flask狼書筆記 | 04_表單的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!