Flask框架之?dāng)?shù)據(jù)交互的實(shí)現(xiàn)
1 使用Flask處理表單
什么是表單(Form)? 表單是搜集用戶數(shù)據(jù)信息的各種表單元素的集合區(qū)域。它的作用是實(shí)現(xiàn)用戶和服務(wù)器的數(shù)據(jù)交互。通過表單搜集客戶端輸入的數(shù)據(jù)信息,如何提交到網(wǎng)站服務(wù)器進(jìn)行處理(搜集錄入/比對(duì)驗(yàn)證等)。Form表單是Web應(yīng)用中最繼承的一部分。為了能處理Form表單,F(xiàn)lask-WTF擴(kuò)展提供了良好的支持。
1.1 使用Flask處理通用表單
Flask請(qǐng)求對(duì)象包括客戶端發(fā)出的所有請(qǐng)求信息,其中,request.form能獲取POST請(qǐng)求中提交的表單數(shù)據(jù)。盡管Flask的請(qǐng)求對(duì)象提供的信息足夠用于處理Web表單,但有些任務(wù)很單調(diào),而且需要重復(fù)操作。
indexhtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<style>
.div1 {
height: 180px;
width: 380px;
border: 1px solid #8A8989;
margin: 0 auto;
}
.input {
display: block;
width: 350px;
height: 40px;
margin: 10px auto;
}
.button {
background: #2066C5;
color: white;
font-size: 18px;
font-weight: bold;
height: 50px;
border-radius: 4px;
}
</style>
<div class="div1">
{# action:接受的路由 #}
<form action="/login" method="post">
<input type="text" class="input" name="username" placeholder="請(qǐng)輸入用戶名">
<input type="password" class="input" name="pwd" placeholder="請(qǐng)輸入密碼">
<input type="submit" value="登錄" class="input button">
</form>
</div>
</body>
</html>
app.py
# @time:2020/11/8 16:18
# Author:Small-J
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template('index5.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return '這是get請(qǐng)求'
else:
return '這是post請(qǐng)求'
if __name__ == '__main__':
app.run(debug=True)
發(fā)送post請(qǐng)求成功

使用Postman發(fā)送Get請(qǐng)求成功

在上面的工程中,對(duì)表單沒有進(jìn)行必要的保護(hù)措施,很容易被人利用,控制用戶在當(dāng)前已登錄的Web應(yīng)用程序上執(zhí)行非本意的操作。因此,在實(shí)際部署服務(wù)器上的代碼時(shí),不建議使用這個(gè)方式處理表單,推薦使用Flask-WTF方式進(jìn)行表單處理。
1.2 使用Flask-WTF處理表單
Flask-WTF的安裝:pip install flask-wtf
啟動(dòng)CSRF保護(hù)
Flask-WTF提供了對(duì)所有Form表單免受跨站請(qǐng)求偽造(Cross-Site Request Forgery, CSRF)攻擊的技術(shù)支持(通過添加動(dòng)態(tài)token令牌的方式)
我們?cè)贔lask根目錄下新增config.py配置文件,要啟動(dòng)CSRF保護(hù),可以在config.py中定義兩個(gè)變量
# @time:2020/11/8 16:54 # Author:Small-J import os import random # 開啟CSRF保護(hù) CSRF_ENABLED = True # 生成密鑰 SECRET_KEY = os.urandom(24)
form.py
# @time:2020/11/8 17:00
# Author:Small-J
# 引入Form元素的基類
from flask_wtf import Form
# 引入Form元素的父類
from wtforms import StringField, PasswordField
# 引入Form驗(yàn)證父類
from wtforms.validators import DataRequired, Length
# 登錄表單類,繼承于Form類
class BaseLogin(Form):
# 用戶名
name = StringField('name', validators=[DataRequired(message="用戶名不能為空"), Length(6, 16, message="長(zhǎng)度為6~16之間")], render_kw={'placeholder': '輸入用戶名'})
# 密碼
password = PasswordField('password', validators=[DataRequired(message="密碼不能為空"), Length(6, 16, message='長(zhǎng)度位于6~16之間')], render_kw={'placeholder': '輸入密碼'})
app.py
# @time:2020/11/8 16:54
# Author:Small-J
from flask import Flask, flash
from flask import url_for, render_template
from flask_wtf.csrf import CSRFProtect
# 導(dǎo)入定義的BaseLogin
from forms import BaseLogin
import config
app = Flask(__name__)
# 配置文件初始化
app.config.from_object(config)
@app.route('/login', methods=['POST', 'GET'])
def base_login():
form = BaseLogin()
# 判斷驗(yàn)證提交是否通過
if form.validate_on_submit():
flash(form.name.data + '|' + form.password.data)
return '表單數(shù)據(jù)提交成功'
else:
return render_template('login.html', form=form)
@app.route('/')
def hello_world():
return 'Hello World'
if __name__ == '__main__':
app.run(debug=True)
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask_WTF</title>
</head>
<body>
<style type="text/css">
.div1 {
height: 180px;
width: 380px;
border: 1px solid #8A8989;
margin: 0 auto;
}
.input {
display: block;
width: 350px;
height: 40px;
margin: 10px auto;
}
.button {
background: #2066C5;
color: white;
font-size: 18px;
font-weight: bold;
height: 50px;
border-radius: 4px;
}
</style>
<div class="div1">
<form action="/login" method="post">
<!--啟動(dòng)CSRF-->
{{ form.hidden_tag() }}
{{ form.name(size=16, id='name', class='input') }}
{% for e in form.name.errors %}
<span style="color: red">{{ e }}</span>
{% endfor %}
{{ form.password(size=16, id='password', class='input') }}
{% for e in form.password.errors %}
<span style="color: red">{{ e }}</span>
{% endfor %}
<input type="submit" value="登錄" class="input button">
</form>
</div>
</body>
</html>
2 使用Flask上傳文件
在Web開發(fā)時(shí),經(jīng)常需要實(shí)現(xiàn)文件上傳功能??梢砸云胀ǚ绞竭M(jìn)行文件的上傳,上傳過程一般要檢查上傳的文件格式是否符合要求,文件保存時(shí)注意絕對(duì)路徑和相對(duì)路徑。
Flask文件上傳比較簡(jiǎn)單,需要注意以下3點(diǎn)要求:
- 一個(gè)標(biāo)簽被標(biāo)記有enctype=multipart/form-data,并且在里面包含一個(gè)input type=file
- 服務(wù)器端應(yīng)用通過請(qǐng)求對(duì)象上的
files字典訪問文件。 - 使用文件的
save()方法將文件永久地保存在文件系統(tǒng)上的某處。 - 注意:表單中必須要求enctype=“multipart/form-data”,否則上傳文件無效。一般可以寫成<form action="" method=“post” enctype=“multipart/form-data”
import os, from os import path指的是導(dǎo)入os模塊及os模塊下的path方法。方法下相關(guān)屬性如下:
os.path.sep: windows下路徑分隔符是反斜杠\;os.path.altsep: linux下路徑分隔符是/根目錄:os.path.curdir當(dāng)前目錄 :os.path.pardir父目錄 :os.path.abspath(path)- 絕對(duì)路徑:
os.path.join()
注意:什么是文件分隔符?將表格轉(zhuǎn)換為文本時(shí),用分隔符標(biāo)識(shí)文件分隔的位置或?qū)⑽谋巨D(zhuǎn)換成表格時(shí),用其標(biāo)識(shí)新行或新列的起始位置。不同操作系統(tǒng)下文件分隔符是不同的,Windows中是"", Linux中是"/"
# @time:2020/11/8 21:48
# Author:Small-J
# 導(dǎo)入secure_filename方法,將中文文件名傳給secure_filename
from werkzeug.utils import secure_filename
from flask import Flask, render_template, request
import os
from os import path
app = Flask(__name__)
# 指定該路由可以使用的請(qǐng)求方式,get和post請(qǐng)求兩種方式
@app.route('/', methods=['POST', 'GET'])
def hello_world():
# method : 請(qǐng)求的方法
if request.method == 'GET':
return render_template('upload.html')
else:
# request.files:代表著獲取文件流
# 這里接受的file指的是對(duì)應(yīng)name對(duì)應(yīng)的值
f = request.files['file']
# 去掉其中文命名
filename = secure_filename(f.filename)
# save : 字節(jié)保存語句拼接
f.save(path.join('static/uploads', filename))
return "上傳文件成功!"
if __name__ == '__main__':
app.run(debug=True)
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上傳</title>
<style type="text/css">
.div1 {
height: 180px;
width: 380px;
border: 1px solid #8A8989;
margin: 0 auto;
}
.input {
display: block;
width: 250px;
height: 30px;
margin: 10px auto;
}
.button {
background: #2066C5;
color: white;
font-size: 18px;
font-weight: bold;
height: 30px;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="div1">
{# 當(dāng)選擇文件上傳的時(shí)候,我們需要使用到enctype,否則是無法上傳使用的 #}
{# multipart/form-data:在使用包含文件上傳控件的表單時(shí),必須使用該值 #}
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file" class="input">
<input type="submit" value="上傳" class="input button">
</form>
</div>
</body>
</html>
上傳文件

3 Cookie的使用
Cookie有時(shí)也記作Cookies,它現(xiàn)在經(jīng)常被大家提到,那么到底什么是Cookies?它有什么作用呢?Cookies是一種能夠讓服務(wù)器把少量數(shù)據(jù)儲(chǔ)存到客戶端的硬盤或內(nèi)存,或是從客戶端的硬盤讀取數(shù)據(jù)的一種技術(shù)。當(dāng)你再次瀏覽某網(wǎng)站時(shí),瀏覽器將存放于本地的用戶身份信息遞交給服務(wù)器,服務(wù)器就可以識(shí)別用戶的身份
3.1 Cookie的基本概念
當(dāng)用戶訪問服務(wù)器并登錄成功后,服務(wù)器向客戶端返回的一些數(shù)據(jù)(Cookie),客戶端將服務(wù)器返回的Cookie數(shù)據(jù)保存在本地,當(dāng)用戶再次訪問服務(wù)器時(shí),瀏覽器自動(dòng)攜帶Cookie數(shù)據(jù)給服務(wù)器,服務(wù)器便自動(dòng)訪問者的身份信息。
Cookie基本的語法:set_cookie(name, value, expire, path, domain, secure)
| 參數(shù) | 描述 |
|---|---|
| name | 必需項(xiàng),規(guī)定Cookie的名稱 |
| value | 必需項(xiàng),規(guī)定Cookie的值 |
| expire | 可選項(xiàng),規(guī)定Cookie的有效期 |
| path | 可選項(xiàng),規(guī)定Cookie在當(dāng)前Web下哪些目錄有效 |
| domain | 可選項(xiàng),規(guī)定Cookie作用的有效域名 |
| secure | 可選項(xiàng),規(guī)定是否通過安全的HTTPS連接來傳輸Cookie |
3.2 Cookie的基本使用
我們?cè)贔lask中自定義Cookie,實(shí)際上就是在相應(yīng)Response的Set-Cookie字段中新增加自定義的鍵值對(duì)。而獲取Cookie,就是在請(qǐng)求Request中通過鍵獲取對(duì)應(yīng)的值,所以,在工程中必須引入Request和Response模塊。
設(shè)置Cookie
設(shè)置Cookie主要有兩種方法,一種是通過Response對(duì)象設(shè)置,另一種是通過直接設(shè)置表單頭來實(shí)現(xiàn)。
# @time:2020/11/9 13:20
# Author:Small-J
from flask import Flask, request, Response
app = Flask(__name__)
@app.route('/')
def set_cookie():
# 創(chuàng)建響應(yīng)
resp = Response("設(shè)置Cookie!")
# 設(shè)置Cookie名稱
resp.set_cookie('username', 'Small-J')
return resp
if __name__ == '__main__':
app.run(debug=True)


查看Cookie
查看已經(jīng)設(shè)置好的Cookie,可以通過request.cookies.get來得到
@app.route('/get_cookie')
def get_cookie():
# 可通過請(qǐng)求cookies方式來獲取
username = request.cookies.get('username')
return username
刪除Cookie
刪除已經(jīng)設(shè)置好的Cookie,可以通過delete_cookie()來完成。delect_cookie括號(hào)中對(duì)象為被刪除的對(duì)象名,比如delect_cookie("username")
@app.route('/del_cookie')
def del_cookie():
# 創(chuàng)建響應(yīng)
resp = Response('刪除Cookie')
# 刪除Cookie
resp.delete_cookie("username")
return resp
4 Session的使用
Session是基于Cookie實(shí)現(xiàn)的,保存在服務(wù)器的鍵值對(duì)(session[‘name’] = ‘value’)中。同時(shí),在瀏覽器的Cookie也對(duì)應(yīng)一個(gè)相同的隨機(jī)字符串,用來再次請(qǐng)求的時(shí)驗(yàn)證
注意:Session是存儲(chǔ)在服務(wù)器中的,Cookies是儲(chǔ)存在瀏覽器本地中,而Flask的Session是基于Cookies,Session是經(jīng)過加密保存在Cookies中。
4.1 Session的基本配置
因?yàn)镕lask的Session是通過加密之后放在了Cookie中。有加密就有密鑰用于解密,所以,用到了Flask的Sessio模塊就一定要配置SECRET_KEY這個(gè)全局宏。一般將SECRET_KEY設(shè)置為24位的字符。我們可以自己設(shè)定一個(gè)隨機(jī)字符串,例如:
app.config['SECRET_KEY'] = XXXXXXX
我們也可以引入OS模塊中,自動(dòng)產(chǎn)生一個(gè)24位的隨機(jī)字符串函數(shù)。這種方法有個(gè)不足之處,就是服務(wù)器每次啟動(dòng)之后這個(gè)SECRET_KEY的值是不一樣的,會(huì)造成Session驗(yàn)證失效,用戶只有重新登錄。
4.2 Session的基本使用
設(shè)置Session
設(shè)置Session主要是通過session['name'] = 'value'方法來完成,name代表的是變量名稱,value代表的是變量的值
# @time:2020/11/9 16:59
# Author:Small-J
from flask import Flask, session
import os
app = Flask(__name__)
# 產(chǎn)生SECRET_KEY值
app.config['SECRET_KEY'] = os.urandom(24)
@app.route('/')
def set_session():
session['username'] = 'Small-J'
return 'Session設(shè)置成功'

獲取Session的值
獲取Session的值有兩種方法
session['name']: 如果內(nèi)容不存在,將會(huì)報(bào)異常session.get('name'): 如果內(nèi)容不存在,將會(huì)返回None
class GetSession(views.View):
"""獲取session的值"""
def dispatch_request(self):
username = session.get('username')
return username or "Session為空"
# 添加路由規(guī)則
app.add_url_rule(rule='/get_session', endpoint='get_session', view_func=GetSession.as_view('session'))
刪除Session的值或清空Session所有值
刪除單個(gè)Session的值,可以使用Session.pop('key')這個(gè)方法,如果清除多個(gè)Session的值,可以使用Session.clear方法
class DelSession(views.View):
"""刪除session的值"""
def dispatch_request(self):
# 刪除單個(gè)session
session.pop('username')
# 清空
# session.clear()
return 'Session被刪除'

設(shè)置Session的過期時(shí)間
如果沒有指定Session的過期時(shí)間,那么默認(rèn)就是瀏覽器關(guān)閉后自動(dòng)結(jié)束,即關(guān)閉瀏覽器失效。session.permanent=True在Flask下則可以將有效期延長(zhǎng)至一個(gè)月。下面的方法可以配置具體多少天的有效期。
如果設(shè)置了Session的permanent屬性為True,那么過期時(shí)間是31天。
可以通過給app.config設(shè)置PERMANENT_SESSION_LIFETIME來更改過期時(shí)間
在實(shí)際項(xiàng)目開發(fā)中可能還有一種需求,就是指定Session的失效時(shí)間為3天、7天、10天等整數(shù)天數(shù)的情況,這里主要用到了一個(gè)持續(xù)久化的會(huì)話生成的時(shí)間(實(shí)質(zhì)就是Session會(huì)話的有效期)PERMANENT_SESSION_LIFETIME,作為一個(gè)datetime.timedelta對(duì)象
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
到此這篇關(guān)于Flask框架之?dāng)?shù)據(jù)交互的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Flask 數(shù)據(jù)交互內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
對(duì)python3 中方法各種參數(shù)和返回值詳解
今天小編就為大家分享一篇對(duì)python3 中方法各種參數(shù)和返回值詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-12-12
一文詳解Python中PO模式的設(shè)計(jì)與實(shí)現(xiàn)
在使用 Python 進(jìn)行編碼的時(shí)候,會(huì)使用自身自帶的編碼設(shè)計(jì)格式,比如說最常見的單例模式等。本文將為大家介紹PageObject自動(dòng)化設(shè)計(jì)模式(PO模式)的設(shè)計(jì)與實(shí)現(xiàn),感興趣的可以了解一下2022-06-06
linux之文件查找指定文件中包含關(guān)鍵字的行信息方式
這篇文章主要介紹了linux之文件查找指定文件中包含關(guān)鍵字的行信息方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2023-06-06
Python調(diào)用PC攝像頭實(shí)現(xiàn)掃描二維碼
PC攝像機(jī)掃描二維碼的應(yīng)用場(chǎng)景很廣泛,可以應(yīng)用于各種需要快速掃描、識(shí)別和管理的場(chǎng)景,本文就來具體講講如何用Python實(shí)現(xiàn)這一功能吧2023-05-05
解決Jupyter Notebook使用parser.parse_args出現(xiàn)錯(cuò)誤問題
這篇文章主要介紹了解決Jupyter Notebook使用parser.parse_args出現(xiàn)錯(cuò)誤問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-04-04

