Flask-WTF與WTForms的用法詳解

前言

我們?cè)谑褂胒lask框架來搭建自己的博客淮腾,只要是設(shè)涉及到表單相關(guān)糟需,必然會(huì)想起Flask-WTF與WTForms。對(duì)于flask初學(xué)者來說来破,比較容易混淆兩者篮灼。今天想來一一解釋兩者的用法。

Flask-WTF

基本了解

Flask-WTF是集成WTForms徘禁,并帶有 csrf 令牌的安全表單和全局的 csrf 保護(hù)的功能诅诱。
每次我們?cè)诮⒈韱嗡鶆?chuàng)建的類都是繼承與flask_wtf中的FlaskForm,而FlaskForm是繼承WTForms中forms送朱。

用法:

1.創(chuàng)建基礎(chǔ)表單

例如娘荡,form.py:

class LoginForm(FlaskForm):
    username = StringField()
    password = PasswordField()
    remember_me = BooleanField(label='Keep me logged in')
2.CSRF保護(hù)

任何使用FlaskForm創(chuàng)建的表單發(fā)送請(qǐng)求,都會(huì)有CSRF的全部保護(hù)驶沼,在對(duì)應(yīng)的template中HTML渲染表單時(shí)炮沐,可以加入form.csrf_token:

<form method="post">
    {{ form.csrf_token }}
</form>

但是如果模板中沒有表單,則可以使用一個(gè)隱藏的input標(biāo)簽加入csrf_token回怜。

<form method="post">
    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
</form>
3.驗(yàn)證表單

在視圖處理程序中驗(yàn)證請(qǐng)求:
view.py

def login():
    form = LoginForm()
    if form.validate_on_submit():
        return redirect('/success')
    return render_template('login.html', form=form)

使用validate_on_submit 來檢查是否是一個(gè) POST 請(qǐng)求并且請(qǐng)求是否有效大年。

4.文件上傳

Flask-WTF 提供 FileField 來處理文件上傳,它在表單提交后,自動(dòng)從 flask.request.files 中抽取數(shù)據(jù)翔试。FileFielddata 屬性是一個(gè) Werkzeug FileStorage 實(shí)例轻要。

from werkzeug import secure_filename
from flask_wtf.file import FileField

class PhotoForm(Form):
    photo = FileField('Your photo')

@app.route('/upload/', methods=('GET', 'POST'))
def upload():
    form = PhotoForm()
    if form.validate_on_submit():
        filename = secure_filename(form.photo.data.filename)
        form.photo.data.save('uploads/' + filename)
    else:
        filename = None
    return render_template('upload.html', form=form, filename=filename)

注意:在 HTML 表單的 enctype 設(shè)置成 multipart/form-data,如下:

<form action="/upload/" method="POST" enctype="multipart/form-data">
    ....
</form>
5.驗(yàn)證碼

Flask-WTF 通過 RecaptchaField 也提供對(duì)驗(yàn)證碼的支持:

from flask_wtf import Form, RecaptchaField
from wtforms import TextField

class SignupForm(Form):
    username = TextField('Username')
    recaptcha = RecaptchaField()

還需要配置一下信息:

字段 配置
RECAPTCHA_PUBLIC_KEY 必須 公鑰
RECAPTCHA_PRIVATE_KEY 必須 私鑰
RECAPTCHA_API_SERVER 可選 驗(yàn)證碼 API 服務(wù)器
RECAPTCHA_PARAMETERS 可選 一個(gè) JavaScript(api.js)參數(shù)的字典
RECAPTCHA_DATA_ATTRS 可選 一個(gè)數(shù)據(jù)屬性項(xiàng)列表 https://developers.google.com/recaptcha/docs/display

WTForms

基本了解

WTForms是一個(gè)Flask集成的框架垦缅,或者是說庫冲泥。用于處理瀏覽器表單提交的數(shù)據(jù)。它在Flask-WTF 的基礎(chǔ)上擴(kuò)展并添加了一些隨手即得的精巧的幫助函數(shù)壁涎,這些函數(shù)將會(huì)使在 Flask 里使用表單更加有趣凡恍。

用法:

1.field字段

WTForms支持HTML字段:

字段類型 說明
StringField 文本字段, 相當(dāng)于type類型為text的input標(biāo)簽
TextAreaField 多行文本字段
PasswordField 密碼文本字段
HiddenField 隱藏文本字段
DateField 文本字段怔球, 值為datetime.date格式
DateTimeField 文本字段嚼酝, 值為datetime.datetime格式
IntegerField 文本字段, 值為整數(shù)
DecimalField 文本字段竟坛, 值為decimal.Decimal
FloatField 文本字段革半, 值為浮點(diǎn)數(shù)
BooleanField 復(fù)選框, 值為True 和 False
RadioField 一組單選框
SelectField 下拉列表
SelectMultipleField 下拉列表流码, 可選擇多個(gè)值
FileField 文件上傳字段
SubmitField 表單提交按鈕
FormFiled 把表單作為字段嵌入另一個(gè)表單
FieldList 子組指定類型的字段
2.Validators驗(yàn)證器

WTForms可以支持很多表單的驗(yàn)證函數(shù):

驗(yàn)證函數(shù) 說明
Email 驗(yàn)證是電子郵件地址
EqualTo 比較兩個(gè)字段的值; 常用于要求輸入兩次密鑰進(jìn)行確認(rèn)的情況
IPAddress 驗(yàn)證IPv4網(wǎng)絡(luò)地址
Length 驗(yàn)證輸入字符串的長(zhǎng)度
NumberRange 驗(yàn)證輸入的值在數(shù)字范圍內(nèi)
Optional 無輸入值時(shí)跳過其它驗(yàn)證函數(shù)
DataRequired 確保字段中有數(shù)據(jù)
Regexp 使用正則表達(dá)式驗(yàn)證輸入值
URL 驗(yàn)證url
AnyOf 確保輸入值在可選值列表中
NoneOf 確保輸入值不在可選列表中
3.自定義Validators驗(yàn)證器

第一種: in-line validator(內(nèi)聯(lián)驗(yàn)證器)
也就是自定義一個(gè)驗(yàn)證函數(shù)延刘,在定義表單類的時(shí)候漫试,在對(duì)應(yīng)的字段中加入該函數(shù)進(jìn)行認(rèn)證。下面的my_length_check函數(shù)就是用于判name字段長(zhǎng)度不能超過50.

def my_length_check(form, field):
    if len(field.data) > 50:
        raise ValidationError('Field must be less than 50 characters')

class MyForm(Form):
    name = StringField('Name', [InputRequired(), my_length_check])

第二種:通用且可重用的驗(yàn)證函數(shù)
一般是以validate開頭碘赖,加上下劃線再加上對(duì)應(yīng)的field字段(validate_filed)驾荣,瀏覽器在提交表單數(shù)據(jù)時(shí),會(huì)自動(dòng)識(shí)別對(duì)應(yīng)字段所有的驗(yàn)證器普泡,然后執(zhí)行驗(yàn)證器進(jìn)行判斷播掷。

class RegistrationForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Length(1, 60), Email()])
    username = StringField('Username', validators=[DataRequired(), Length(1, 60),
        Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0, 'username must have only letters, numbers dots or underscores')])
    password = PasswordField('Password', validators=[DataRequired(), EqualTo('password2', message='password must match')])
    password2 = PasswordField('Confirm password', validators=[DataRequired()])

    def validate_email(self, field):
        if User.objects.filter(email=field.data).count() > 0:
            raise ValidationError('Email already registered')

    def validate_username(self, field):
        if User.objects.filter(username=field.data).count() > 0:
            raise ValidationError('Username has exist')

第三種:比較高級(jí)的validators

class Length(object):
    def __init__(self, min=-1, max=-1, message=None):
        self.min = min
        self.max = max
        if not message:
            message = u'Field must be between %i and %i characters long.' % (min, max)
        self.message = message

    def __call__(self, form, field):
        l = field.data and len(field.data) or 0
        if l < self.min or self.max != -1 and l > self.max:
            raise ValidationError(self.message)

length = Length
4.Widget組件

下面可以以登錄界面為實(shí)例:
login.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms import validators
from wtforms import widgets

class LoginForm(Form):
    name = simple.StringField(
        label='用戶名',
        validators=[
            validators.DataRequired(message='用戶名不能為空.'),
        ],
        widget=widgets.TextInput(),
        render_kw={'class': 'form-control'}
    )
    pwd = simple.PasswordField(
        label='密碼',
        validators=[
            validators.DataRequired(message='密碼不能為空.'),
        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )

總結(jié)

其實(shí)flask表單這一部分我們都是使用Flask-WTF與WTForms來進(jìn)行實(shí)現(xiàn),比如說做一下簡(jiǎn)單的系統(tǒng)登錄界面撼班、注冊(cè)界面等等歧匈,可以利用它們來做一些小demo,你就可以深入理解它的原理并且可以強(qiáng)化flask的基礎(chǔ)砰嘁。如果不懂的件炉,也希望大家可以參考我最近做的開源項(xiàng)目SimpleBlog,里面大量應(yīng)用到Flask-WTF與WTForms。

參考鏈接:
1.https://wtforms.readthedocs.io/en/stable/
2.https://flask-wtf.readthedocs.io/en/stable/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矮湘,一起剝皮案震驚了整個(gè)濱河市斟冕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缅阳,老刑警劉巖磕蛇,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡秀撇,警方通過查閱死者的電腦和手機(jī)超棺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捌袜,“玉大人说搅,你說我怎么就攤上這事÷驳龋” “怎么了弄唧?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)霍衫。 經(jīng)常有香客問我候引,道長(zhǎng),這世上最難降的妖魔是什么敦跌? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任澄干,我火速辦了婚禮,結(jié)果婚禮上柠傍,老公的妹妹穿的比我還像新娘麸俘。我一直安慰自己,他們只是感情好惧笛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布从媚。 她就那樣靜靜地躺著,像睡著了一般患整。 火紅的嫁衣襯著肌膚如雪拜效。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天各谚,我揣著相機(jī)與錄音紧憾,去河邊找鬼。 笑死昌渤,一個(gè)胖子當(dāng)著我的面吹牛赴穗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膀息,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼望抽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了履婉?” 一聲冷哼從身側(cè)響起煤篙,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毁腿,沒想到半個(gè)月后辑奈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苛茂,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年鸠窗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妓羊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稍计,死狀恐怖躁绸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情臣嚣,我是刑警寧澤净刮,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站硅则,受9級(jí)特大地震影響淹父,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怎虫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望大审。 院中可真熱鬧蘸际,春花似錦、人聲如沸徒扶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酷愧。三九已至,卻和暖如春缠诅,著一層夾襖步出監(jiān)牢的瞬間溶浴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工管引, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留士败,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓褥伴,卻偏偏與公主長(zhǎng)得像谅将,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子重慢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 22年12月更新:個(gè)人網(wǎng)站關(guān)停饥臂,如果仍舊對(duì)舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,182評(píng)論 22 257
  • 第4章 Web表單 我們?cè)诘诙陆榻B過請(qǐng)求對(duì)象,它包含有客戶端請(qǐng)求的全部信息似踱。尤其是隅熙,可以通過request.fo...
    易木成華閱讀 1,025評(píng)論 0 1
  • 【Chapter 4】 Web 表單 4.1 跨站請(qǐng)求偽造保護(hù) 默認(rèn)情況下稽煤,F(xiàn)lask-WTF 能保護(hù)所有表單免受...
    蜘蛛的夢(mèng)囈閱讀 477評(píng)論 0 2
  • 請(qǐng)求對(duì)象包含客戶端發(fā)出的所有請(qǐng)求信息。其中 request.form 能獲取 POST 請(qǐng)求中提交的表單數(shù)據(jù)囚戚。 我...
    焉知非魚閱讀 1,133評(píng)論 0 2
  • 總是不自覺把自己想法強(qiáng)加給別人酵熙。當(dāng)我們自以為很對(duì)的事硬是強(qiáng)加給至親之人,其實(shí)很多對(duì)的事自己都辦不到卻要他人做到...
    愛叨叨e牛閱讀 133評(píng)論 0 0