20201106-第十二講-Flask-補(bǔ)充WTForms表單驗(yàn)證浑此、cookie的基本使用

Flask-補(bǔ)充WTForms表單驗(yàn)證

Flask-WTF

Flask-WTF是簡(jiǎn)化了WTForms操作的一個(gè)第三方庫(kù)昆著。WTForms表的二個(gè)主要功能是驗(yàn)證用戶提交數(shù)據(jù)的合法性以及渲染模板惧辈。當(dāng)然還包括一些其他功能:CSRF保護(hù)封锉,文件上傳等莽使。安裝Flask-WTF默認(rèn)也會(huì)安裝WTForms锐极,因此使用以下命令安裝Flask-WTF

1?pip install flask-wtf

表單驗(yàn)證

安裝完Flask-WTF后,來(lái)看下第一個(gè)功能芳肌,就是用表單來(lái)做數(shù)據(jù)驗(yàn)證灵再,現(xiàn)在有一個(gè)forms.py文件,然后再里面創(chuàng)建一個(gè)RegistForm的注冊(cè)驗(yàn)證表單

1 class RegistForm(Form):

2? ? ? ? name = StringField(validators=[length(min=4,max=25)])

3? ? ? ? email = StringField(validators=[email()])

4? ? ? ? password = StringField(validators=[DataRequired(),length(min=6,max=10),EqualTo('confirm')])

5? ? ? ? confirm = StringField()

在這個(gè)表單里面指定需要上傳的參數(shù)亿笤,且指定了驗(yàn)證器翎迁,比如name的長(zhǎng)度應(yīng)該在4-25之間。email必須要滿足郵箱的格式净薛。password長(zhǎng)度必須在6-10之間汪榔,并且應(yīng)該和confirm相等才能通過(guò)驗(yàn)證

寫完表單后,接下來(lái)就是regist.html文件

1 <form action="/regist/" method="POST">

2? ? ? ? <table>

3? ? ? ? ? ? ? <tr>

4? ? ? ? ? ? ? ? ? <td>用戶名:</td>

5? ? ? ? ? ? ? ? ? <td><input type="text" name="name"></td>

6? ? ? ? ? ? ? </tr>

7? ? ? ? ? ? ? <tr>

8? ? ? ? ? ? ? ? ? <td>郵箱:</td>

9? ? ? ? ? ? ? ? ? <td><input type="email" name="email"></td>

10? ? ? ? ? ? </tr>

11? ? ? ? ? ? <tr>

12? ? ? ? ? ? ? ? ? <td>密碼:</td>

13? ? ? ? ? ? ? ? ? <td><input type="password" name="password"></td>

14? ? ? ? ? ? </tr>

15? ? ? ? ? ? <tr>?

16? ? ? ? ? ? ? ? <td>確認(rèn)密碼:</td>

17? ? ? ? ? ? ? ? <td><input type="password" name="confirm"></td>

18? ? ? ? ? ? </tr>

19? ? ? ? ? ? <tr>

20? ? ? ? ? ? ? ? ?<td></td>

21? ? ? ? ? ? ? ? <td><input type="submit" value="提交"></td>

22? ? ? ? ? ? </tr>

23? ? ? ? </table>

24 </form>

再來(lái)看視圖函數(shù)regist

1 @app.route('/regist/',methods=['POST','GET'])

2 def regist():

3? ? ? ? form = RegistForm(request.form)

4? ? ? ? if request.method == 'POST' and form.validate():

5? ? ? ? ? ? ? user = User(name=form.name.data,email=form.email.data,password=form.password.data)

6? ? ? ? ? ? ? db.session.add(user)

7? ? ? ? ? ? ? db.session.commit()

8? ? ? ? ? ? ? return '注冊(cè)成功!'

9? ? ? ? return render_template('regist.html')

RegistForm傳遞的是request.form進(jìn)去進(jìn)行初始化肃拜,并且判斷form.validate會(huì)返回用戶提交的數(shù)據(jù)是否滿足表單的驗(yàn)證

渲染模板

form還可以渲染模板痴腌,讓你少寫了一些代碼,比如重寫以上例子燃领,RegistForm表單代碼如下

1 class RegistForm(Form):

2? ? ? ? name = StringField('用戶名:',validators=[length(min=4,max=25)])

3? ? ? ? email = StringField('郵箱:'validators=[email()])

4? ? ? ? password = StringField('密碼:',validators=[DataRequired(),length(min=6,max=10),EqualTo('confirm')])

5? ? ? ? confirm = StringField('確認(rèn)密碼:')

以上增強(qiáng)了第一個(gè)位置參數(shù)士聪,用來(lái)在html文件中,做標(biāo)簽提示作用猛蔽。

在app中的視圖函數(shù)中剥悟,修改為如下

@app.route('/regist/',methods=['POST','GET'])

def regist():

? ? form = RegistForm(request.form)

? ? if request.method == 'POST' and form.validate():

? ? ? ? user = User(name=form.name.data,email=form.email.data,password=form.password.data)

? ? ? ? db.session.add(user)

? ? ? ? db.session.commit()

? ? ? ? return '注冊(cè)成功!'

? ? return render_template('regist.html',form=form)

以上唯一的不同是在渲染模板是傳入了form表單參數(shù)進(jìn)去,這樣在模板中就可以使用表單form變量了。

就下來(lái)看下regist.html文件

<form action="/regist/" method="POST">

? ? <table>

? ? ? ? <tr>

? ? ? ? ? ? <td>{{ form.name.label }}</td>

? ? ? ? ? ? <td>{{ form.name() }}</td>

? ? ? ? </tr>

? ? ? ? <tr>

? ? ? ? ? ? <td>{{ form.email.label }}</td>

? ? ? ? ? ? <td>{{ form.email() }}</td>

? ? ? ? </tr>

? ? ? ? <tr>

? ? ? ? ? ? <td>{{ form.password.label }}</td>

? ? ? ? ? ? <td>{{ form.password() }}</td>

? ? ? ? </tr>

? ? ? ? <tr>

? ? ? ? ? ? <td>{{ form.confirm.label }}</td>

? ? ? ? ? ? <td>{{ form.confirm() }}</td>

? ? ? ? </tr>

? ? ? ? <tr>

? ? ? ? ? ? <td></td>

? ? ? ? ? ? <td><input type="submit" value="提交"></td>

? ? ? ? </tr>

? ? </table>

</form>

文件上傳

1.在模板中懦胞,form表單中替久,需要指定encotype='multipart/form-data'才能上傳文件。

2.在后臺(tái)如想要獲取上傳文件躏尉,那么應(yīng)該使用request.files.get(’avatar')來(lái)獲取蚯根。

3.保存文件之前,先要使用werkzeug.utils.secure_filename來(lái)對(duì)上傳上來(lái)的文件名進(jìn)行一個(gè)過(guò)濾胀糜。這樣才能保證不會(huì)有安全問(wèn)題颅拦。

4.獲取到上傳上來(lái)的文件后,使用avatar.save(路徑)方法來(lái)保存文件教藻。

5.從服務(wù)器上讀取文件后距帅,應(yīng)該定義一個(gè)url與視圖函數(shù),來(lái)獲取指定的文件括堤。在這個(gè)視圖函數(shù)中碌秸,使用send_from_directory(文件的目錄,文件名)來(lái)獲取悄窃。

@app.route('/upload/',methods=['GET','POST'])

def upload():

? ? if request.method == 'GET':

? ? ? ? return render_template('upload.html')

? ? else:

? ? ? ? # 獲取描述信息

? ? ? ? desc = request.form.get("desc")

? ? ? ? avatar = request.files.get("avatar")

? ? ? ? filename = secure_filename(avatar.filename)

? ? ? ? avatar.save(os.path.join(UPLOAD_PATH,filename))

? ? ? ? print(desc)

? ? ? ? return '文件上傳成功'

@app.route('/images/<filename>/')

def get_image(filename):

? ? return send_from_directory(UPLOAD_PATH,filename)

對(duì)上傳文件使用表單驗(yàn)證:

1.定義表單時(shí)讥电,對(duì)文件的字段,需要采用FileField這個(gè)類型轧抗。

2.驗(yàn)證器應(yīng)該從flask_wtf.file中導(dǎo)入恩敌。flask_wtf.file.FileRequired是用來(lái)驗(yàn)證文件上傳是否為空。flask_wtf.file.FileAllowed用來(lái)驗(yàn)證上傳的文件的后綴名横媚。

3.在視圖文件中纠炮,使用from werkzeug.datastructures import CombinedMultiDict來(lái)把request.form與request.files 來(lái)進(jìn)行合并。再傳給表單來(lái)驗(yàn)證灯蝴。

1 from werkzeug.datastructures import CombinedMultiDict

2 form = UploadForm(CombinedMultiDict([request.form,request.files]))


cookie和session

1.cookie:在網(wǎng)站中恢口,http請(qǐng)求是無(wú)狀態(tài)的。即使第一次和服務(wù)器連接后且登錄成功后穷躁,第二次請(qǐng)求服務(wù)器依然不能知道當(dāng)前請(qǐng)求是那個(gè)用戶弧蝇。cookie的出現(xiàn)就是為了解決此問(wèn)題,第一次登錄后服務(wù)器返回?cái)?shù)據(jù)(cookie)給瀏覽器折砸,然后瀏覽器保存在本地,當(dāng)該用戶發(fā)送第二次請(qǐng)求時(shí)沙峻,就會(huì)自動(dòng)把上次請(qǐng)求存貯的cookie數(shù)據(jù)自動(dòng)的攜帶給服務(wù)器睦授,服務(wù)器通過(guò)瀏覽器攜帶的數(shù)據(jù)就能判斷當(dāng)前用戶是那個(gè)了。cookie存貯的數(shù)據(jù)量有限摔寨,不同的瀏覽器有不同的儲(chǔ)存大小去枷,但一般不超過(guò)4KB。因此使用cookie只能儲(chǔ)存一些小量的數(shù)據(jù)。

2.session:session和cookie的作用有點(diǎn)類似删顶,都是為了儲(chǔ)存用戶相關(guān)的信息竖螃。不同的是,cookie是儲(chǔ)存在本地瀏覽器逗余,session是一個(gè)思路特咆、一個(gè)概念、一個(gè)服務(wù)器儲(chǔ)存授權(quán)信息的解決方案录粱,不同的框架腻格,不同的語(yǔ)言有不同的實(shí)現(xiàn)。雖然實(shí)現(xiàn)不一樣啥繁,但他們的目的都是服務(wù)器為了方便存儲(chǔ)數(shù)據(jù)的菜职。session的出現(xiàn),是為了解決cookie存儲(chǔ)不安全的問(wèn)題的旗闽。

3.cookie和session結(jié)合使用:web開(kāi)發(fā)發(fā)展至今酬核,cookie和session的使用已經(jīng)出現(xiàn)了一次非常成熟的方案。在如今的市場(chǎng)或者企業(yè)里适室,一般有二種存儲(chǔ)方式:

嫡意。存儲(chǔ)服務(wù)端:通過(guò)cookie存儲(chǔ)一個(gè)session_id,然后具體的數(shù)據(jù)是保存在session中。如果用戶已經(jīng)登錄亭病,則服務(wù)器會(huì)在cookie中保存一個(gè)session_id鹅很,下次再請(qǐng)求時(shí),會(huì)把該session_id攜帶上來(lái)罪帖,服務(wù)器根據(jù)session_id在session庫(kù)中獲取用戶的session數(shù)據(jù)促煮。就能知道該用戶到底是誰(shuí),以及之前保存的一些狀態(tài)信息整袁。這種專業(yè)術(shù)語(yǔ)叫server side session菠齿。存儲(chǔ)在服務(wù)器的數(shù)據(jù)會(huì)更加的安全,不容易被竊取坐昙。但存儲(chǔ)在服務(wù)器也有一定的弊端绳匀,會(huì)占用服務(wù)器色資源,但現(xiàn)在服務(wù)器已經(jīng)發(fā)展至今炸客,一些session信息還是卓卓有余的疾棵。

。將session數(shù)據(jù)加密痹仙,然后存儲(chǔ)在cookie中是尔。這種專業(yè)術(shù)語(yǔ)叫client side session。flask采用的就是這種方式开仰,但也可以替換成其他形式拟枚。

flask中使用cookie和session

1.cookie:在Flask中操作cookie薪铜,是通過(guò)response對(duì)象來(lái)操作,可以在response返回之前恩溅,通過(guò)response.set_cookie來(lái)設(shè)置隔箍,這個(gè)方法有一下幾個(gè)參數(shù)需要注意:

key:設(shè)置的cookie的key。

value:key對(duì)應(yīng)的value脚乡。

max_age:改cookie的過(guò)期時(shí)間蜒滩,如果不設(shè)置,則瀏覽器關(guān)閉后就會(huì)自動(dòng)過(guò)期每窖。

expires:過(guò)期時(shí)間帮掉,應(yīng)該是一個(gè)datetime類型

domain:該cookie在那個(gè)域名中有效。一般設(shè)置子域名窒典,比如cms.example.com蟆炊。

path:該cookie在哪個(gè)路徑下有效。

2.session:Flask中的session是通過(guò)from flask import session瀑志。然后添加值key和value進(jìn)去既可涩搓。并且,F(xiàn)lask中的session機(jī)制是將session信息加密劈猪,然后存儲(chǔ)在cookie中昧甘。專業(yè)術(shù)語(yǔ)叫client side session。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末战得,一起剝皮案震驚了整個(gè)濱河市充边,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌常侦,老刑警劉巖浇冰,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異聋亡,居然都是意外死亡肘习,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門坡倔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)漂佩,“玉大人,你說(shuō)我怎么就攤上這事罪塔⊥恫酰” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵征堪,是天一觀的道長(zhǎng)墓拜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)请契,這世上最難降的妖魔是什么咳榜? 我笑而不...
    開(kāi)封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮爽锥,結(jié)果婚禮上涌韩,老公的妹妹穿的比我還像新娘。我一直安慰自己氯夷,他們只是感情好臣樱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著腮考,像睡著了一般雇毫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上踩蔚,一...
    開(kāi)封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天棚放,我揣著相機(jī)與錄音,去河邊找鬼馅闽。 笑死飘蚯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的福也。 我是一名探鬼主播局骤,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼暴凑!你這毒婦竟也來(lái)了峦甩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤现喳,失蹤者是張志新(化名)和其女友劉穎凯傲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拿穴,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泣洞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了默色。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片球凰。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖腿宰,靈堂內(nèi)的尸體忽然破棺而出呕诉,到底是詐尸還是另有隱情,我是刑警寧澤吃度,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布甩挫,位于F島的核電站,受9級(jí)特大地震影響椿每,放射性物質(zhì)發(fā)生泄漏伊者。R本人自食惡果不足惜英遭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亦渗。 院中可真熱鬧挖诸,春花似錦、人聲如沸法精。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)搂蜓。三九已至狼荞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帮碰,已是汗流浹背相味。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留收毫,地道東北人攻走。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像此再,于是被迫代替她去往敵國(guó)和親昔搂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354