欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)激活碼778899分享:鴻蒙 面試 學(xué)習(xí) 上傳文件

柚子快報(bào)激活碼778899分享:鴻蒙 面試 學(xué)習(xí) 上傳文件

http://yzkb.51969.com/

深知大多數(shù)程序員,想要提升技能,往往是自己摸索成長(zhǎng),但自己不成體系的自學(xué)效果低效又漫長(zhǎng),而且極易碰到天花板技術(shù)停滯不前!

既有適合小白學(xué)習(xí)的零基礎(chǔ)資料,也有適合3年以上經(jīng)驗(yàn)的小伙伴深入學(xué)習(xí)提升的進(jìn)階課程,涵蓋了95%以上鴻蒙開發(fā)知識(shí)點(diǎn),真正體系化!

由于文件比較多,這里只是將部分目錄截圖出來(lái),全套包含大廠面經(jīng)、學(xué)習(xí)筆記、源碼講義、實(shí)戰(zhàn)項(xiàng)目、大綱路線、講解視頻,并且后續(xù)會(huì)持續(xù)更新

需要這份系統(tǒng)化的資料的朋友,可以戳這里獲取

Flask-Migrate

Flask項(xiàng)目結(jié)構(gòu)重構(gòu)

Flask入門

Flask的介紹

Flask 是一款發(fā)布于2010年非常流行的 Python Web 框架。

特點(diǎn)

1 微框架、簡(jiǎn)潔,給開發(fā)者提供了很大的擴(kuò)展性。

2 Flask和相應(yīng)的插件寫得很好,用起來(lái)很爽。

3 開發(fā)效率非常高,比如使用 SQLAlchemy 的 ORM 操作數(shù)據(jù)庫(kù)可以節(jié)省開發(fā)者大量書寫 sql 的時(shí) 間。

Flask 的靈活度非常之高,他不會(huì)幫你做太多的決策,很多都可以按 照自己的意愿進(jìn)行更改。

比如:

使用 Flask 開發(fā)數(shù)據(jù)庫(kù)的時(shí)候,具體是使用 SQLAlchemy 還是 MongoEngine,選擇權(quán)完全掌握在你自己的手中。 Flask 本身相當(dāng)于一個(gè)內(nèi)核,其他幾乎所有的功能都要用到擴(kuò)展(郵件擴(kuò)展Flask-Mail ,用戶認(rèn)證 Flask-Login ,數(shù)據(jù)庫(kù) Flask-SQLAlchemy ),都需要 用第三方的擴(kuò)展來(lái)實(shí)現(xiàn)。

Flask 沒有默認(rèn)使用的數(shù)據(jù)庫(kù),你可以選擇 MySQL ,也可以用 NoSQL 。 其 WSGI 工具箱采用 Werkzeug (路由模塊),模板引擎則使用 Jinja2 。這兩個(gè)也是 Flask 框架的核心。

擴(kuò)展列表:http://flask.pocoo.org/extensions/

Flask-SQLalchemy:操作數(shù)據(jù)庫(kù);

Flask-script:插入腳本;

Flask-migrate:管理遷移數(shù)據(jù)庫(kù);

Flask-Session:Session存儲(chǔ)方式指定;

Flask-WTF:表單;

Flask-Mail:郵件;

Flask-Bable:提供國(guó)際化和本地化支持,翻譯;

Flask-Login:認(rèn)證用戶狀態(tài);

Flask-OpenID:認(rèn)證;

Flask-RESTful:開發(fā)REST API的工具;

Flask-Bootstrap:集成前端Twitter Bootstrap框架;

Flask-Moment:本地化日期和時(shí)間;

Flask-Admin:簡(jiǎn)單而可擴(kuò)展的管理接口的框架

文檔地址

1 中文文檔(http://docs.jinkan.org/docs/flask/)

2 英文文檔(http://flask.pocoo.org/docs/1.0/)

Flask的安裝

pip install flask

第一個(gè)Flask程序

#從flask包中導(dǎo)入Flask類 from flask import Flask #創(chuàng)建一個(gè)Flask對(duì)象 app = Flask(name) #@app.route:是一個(gè)裝飾器 #@app.route(‘/’)就是將url中 / 映射到hello_world設(shè)個(gè)視圖函數(shù)上面 #以后你訪問我這個(gè)網(wǎng)站的 / 目錄的時(shí)候 會(huì)執(zhí)行hello_world這個(gè)函數(shù),然后將這個(gè)函數(shù)的返回值返回給瀏覽器 @app.route(‘/’) def hello_world(): return ‘hello Flask!’ #啟動(dòng)這個(gè)WEB服務(wù) if name == ‘main’: #默認(rèn)為5000端口 app.run() #app.run(port=8000)

運(yùn)行方式

通過對(duì)象運(yùn)行

運(yùn)行程序時(shí),可以指定運(yùn)行的主機(jī)IP地址,端口

app.run(host=“0.0.0.0”, port=5000) # 127.0.0.1

參數(shù)解釋

host

主機(jī)IP地址,可以不傳 默認(rèn)localhost

port

端口號(hào),可以不傳 默認(rèn)5000

通過Python運(yùn)行方式運(yùn)行

app = Flask(name) @app.route(“/”) def index(): return “hello world” if name == ‘main’: app.run()

提示

如果想在同一個(gè)局域網(wǎng)下的其他電腦訪問自己電腦上的Flask網(wǎng) 站,需要設(shè)置 host=‘0.0.0.0’ 才能訪問得到

通過Flask自帶命令運(yùn)行

app = Flask(name) @app.route(“/”) def index(): return “hello world”

程序中不用再寫app.run()

$ export FLASK_APP=helloworld $ flask run

Running on http://127.0.0.1:5000/

舉例

flask run -h 0.0.0.0 -p 8000

注意 命令行下,可以使用使用簡(jiǎn)寫 可以通過 flask run --help 獲取幫助

Debug模式與配置參數(shù)加載

控制臺(tái)倒是給出了錯(cuò)誤提示信息,但是我們希望在瀏覽器也能有相 應(yīng)的提示信息

開啟Debug模式 運(yùn)行時(shí)傳遞參數(shù)

app.run(debug = True)

通過修改配置參數(shù) config

app.config.update(DEBUG=True)

app.config[‘DEBUG’] = True

app.run()

通過配置文件設(shè)置 config

URL與函數(shù)的映射(動(dòng)態(tài)路由)

URL路徑參數(shù)

比如,有一個(gè)請(qǐng)求訪問的接口地址為 /users/11001 ,其中 11001 實(shí)際上為 具體的請(qǐng)求參數(shù),表明請(qǐng)求 11001 號(hào)用戶的信息。 此時(shí)如何從url中提取出 11001 的數(shù)據(jù)?

@app.route(‘/users/’) def user_info(user_id): print(type(user_id)) return ‘hello user{}’.format(user_id)

其中 ,尖括號(hào)是固定寫法,語(yǔ)法為 , variable 默認(rèn)的 數(shù)據(jù)類型是字符串。 如果需要指定類型,則要寫成 converter:variable ,其中 converter 就是類型名稱,可以有以下幾種:

1 string:如果沒有指定具體的數(shù)據(jù)類型,那么默認(rèn)就是使用 string 數(shù)據(jù)類型。

2 int:數(shù)據(jù)類型只能傳遞 int 類型。

3 float:數(shù)據(jù)類型只能傳遞 float 類型。

4 path:數(shù)據(jù)類型和 string 有點(diǎn)類似,都是可以接收任意的字符串,但是 path 可以接收路徑,也就 是說可以包含斜杠。

5 uuid:數(shù)據(jù)類型只能接收符合 uuid 的字符串。 uuid 是一個(gè)全宇宙都唯一的字符串,一般可以用來(lái) 作為表的主鍵。

6 any:數(shù)據(jù)類型可以在一個(gè) url 中指定多個(gè)路徑。

將上面的例子以整型匹配數(shù)據(jù),可以如下使用:

@app.route(‘/users/int:user_id’) def user_info(user_id): print(type(user_id)) return f’正在獲取 ID {user_id} 的用戶信息’ @app.route(‘/users/’) def user_info(user_id): print(type(user_id)) return f’hello user {user_id}’

注意 若是數(shù)據(jù)與設(shè)置的類型不能匹配,則會(huì)返回 Not Found

PostMan的使用

Postman一款非常流行的API調(diào)試工具。其實(shí),開發(fā)人員用的更多。 因?yàn)闇y(cè)試人員做接口測(cè)試會(huì)有更多選擇,例如Jmeter、soapUI等。 不過,對(duì)于開發(fā)過程中去調(diào)試接口,Postman確實(shí)足夠的簡(jiǎn)單方 便,而且功能強(qiáng)大。 官方網(wǎng)站:https://www.getpostman.com/

安裝

1 Postman最早是作用chrome瀏覽器插件存在的,所以,你可以 到chrome商店搜索下載安裝,因?yàn)椴糠衷?,所以,大家都?huì) 找別人共享的postman插件文件來(lái)安裝。

2 Postman提供了獨(dú)立的安裝包,不再依賴于Chrome瀏覽器了。 同時(shí)支持MAC、Windows和Linux,推薦你使用這種方式安裝。 https://www.postman.com/downloads/

查詢參數(shù)的獲取

例如要獲取 http://127.0.0.1:5000/test/?wd=python&ie=ok的參數(shù)

from flask import Flask,request app = Flask(name) @app.route(‘/’) def index(): wd = request.args.get(‘wd’) ie = request.values.get(‘ie’) return f"Hello! {wd} == {ie}" if name == ‘main’: app.run(debug=True)

使用總結(jié)

如果你的這個(gè)頁(yè)面的想要做 SEO 優(yōu)化,就是被搜索引擎搜索到, 那么推薦使用第一種形式(path的形式)。 如果不在乎搜索引擎優(yōu)化,那么就可以使用第二種(查詢字符 串的形式)。

請(qǐng)求體參數(shù)

from flask import Flask,request app = Flask(name) @app.route(‘/’,methods=[‘POST’]) def index(): uname = request.form.get(‘uname’) pwd = request.values.get(‘pwd’) age = request.form.get(‘a(chǎn)ge’) return f"Hello! {uname} == {pwd} == {age}" if name == ‘main’: app.run(debug=True)

上傳文件

客戶端上傳圖片到服務(wù)器,并保存到服務(wù)器中

from flask import request @app.route(‘/upload’, methods=[‘POST’]) def upload_file(): f = request.files[‘pic’]

with open(‘./demo.png’, ‘wb’) as new_file:

new_file.write(f.read())

f.save(‘./demo.png’) return ‘上傳成功!’

其它參數(shù)

如果想要獲取其他地方傳遞的參數(shù),可以通過Flask提供的request 對(duì)象來(lái)讀取。 不同位置的參數(shù)都存放在request的不同屬性中

?????

from flask import Flask,request app = Flask(name) @app.route(‘/args’) def args(): cookies = request.cookies.get(‘uid’) headers = request.headers.get(‘ContentType’) url = request.url method = request.method return f’上傳成功?。?{cookies} == {headers} =={url} == {method}’ if name ==‘main’: app.run(debug=True)

url_for 函數(shù)

一般我們通過一個(gè) URL就可以執(zhí)行到某一個(gè)函數(shù)。 如果反過來(lái),我們知道一個(gè)函數(shù),怎么去獲得這個(gè) URL呢? url_for 函數(shù)就可以幫我們實(shí)現(xiàn)這個(gè)功能。

注意

url_for 函數(shù)可以接收1個(gè)及以上的參數(shù),他接收函數(shù)名作為第 一個(gè)參數(shù) 如果還出現(xiàn)其他的參數(shù),則會(huì)添加到 URL 的后面作為查詢參 數(shù)。

@app.route(‘/post/list//’) def my_list(page): return ‘my list’ @app.route(‘/’) def hello_world(): return url_for(‘my_list’,page=2,num=8)

return “/post/list/2?num=8”

使用url_for函數(shù)原因

問題 為什么選擇 url_for 而不選擇直接在代碼中拼 URL 的原因有兩點(diǎn):

回答 1 將來(lái)如果修改了 URL ,但沒有修改該 URL 對(duì)應(yīng)的函數(shù)名,就不用到處去替換URL 了 2 url_for() 函數(shù)會(huì)轉(zhuǎn)義一些特殊字符和 unicode 字符串,這些事情 url_for 會(huì)自動(dòng)的幫我們

@app.route(‘/login/’) def login(): return ‘login’ @app.route(‘/’) def hello_world(): return url_for(‘login’, next=‘/’)

/login/?next=/

會(huì)自動(dòng)的將/編碼,不需要手動(dòng)去處理。

url=/login/?next=%2F

技巧

在定義url的時(shí)候,一定要記得在最后加一個(gè)斜杠。 1. 如果不加斜杠,那么在瀏覽器中訪問這個(gè)url的時(shí)候,如果最 后加了斜杠,那么就訪問不到。這樣用戶體驗(yàn)不太好。 2. 搜索引擎會(huì)將不加斜杠的和加斜杠的視為兩個(gè)不同的url。而 其實(shí)加和不加斜杠的都是同一個(gè)url,那么就會(huì)給搜索引擎造成 一個(gè)誤解。加了斜杠,就不會(huì)出現(xiàn)沒有斜杠的情況。

響應(yīng)-重定向

永久性重定向:

http 的狀態(tài)碼是 301,多用于舊網(wǎng)址被廢棄了要轉(zhuǎn)到一個(gè)新的網(wǎng) 址確保用戶的訪問 比如:你輸入 www.jingdong.com 的時(shí)候,會(huì)被重定向到 ww w.jd.com , 因?yàn)?jingdong.com 這個(gè)網(wǎng)址已經(jīng)被廢棄了,被改成 jd.com 所以這種情況下應(yīng)該用永久重定向

暫時(shí)性重定向:

http 的狀態(tài)碼是 302,表示頁(yè)面的暫時(shí)性跳轉(zhuǎn)。 比如:訪問一個(gè)需要權(quán)限的網(wǎng)址,如果當(dāng)前用戶沒有登錄,應(yīng) 該重定向到登錄頁(yè)面, 這種情況下,應(yīng)該用暫時(shí)性重定向。

flask中重定向

重定向是通過 redirect(location,code=302) 這個(gè)函數(shù)來(lái)實(shí)現(xiàn)的, location表示 需要重定向到的 URL, 應(yīng)該配合之前講的 url_for() 函數(shù)來(lái)使用, code 表示采用哪個(gè)重定向,默認(rèn)是 302 也即 暫時(shí)性重定向, 可以 修改成 301 來(lái)實(shí)現(xiàn)永久性重定向

from flask import Flask,request,url_for,redirect app = Flask(name) @app.route(‘/’) def hello_world(): return ‘Hello World!’ @app.route(‘/login/’) def login(): return ‘這是登錄頁(yè)面’ #falsk中重定向 @app.route(‘/profile/’) def proflie(): if request.args.get(‘name’): return ‘個(gè)人中心頁(yè)面’ else:

return redirect(url_for(‘login’))

return redirect(url_for(‘login’),code=302) if name == ‘main’: app.run(debug=True)

響應(yīng)-響應(yīng)內(nèi)容

返回字符串

from flask import redirectd @app.route(‘/return_str’) def return_str(): return “你好,少年”

返回JSON

from flask import jsonify app.config[‘JSON_AS_ASCII’] = False @app.route(‘/return_json1’) def return_json1(): json_dict = { “msg_int”: 10, “msg_str”: “你好,少年” } return jsonify(json_dict) @app.route(‘/return_json2’) def return_json2(): json_dict = { “msg_int”: 10, “msg_str”: “你好,少年” } return json_dict

元組方式

可以返回一個(gè)元組,元組中必須至少包含一個(gè)項(xiàng)目,且項(xiàng)目應(yīng)當(dāng)由 (response, status) 、 (response, headers) 或者 (response, status, headers) 組成。 status 的值會(huì)重載狀態(tài)代碼, headers 是一個(gè)由額外頭部值組成的列表 或字 典 status 值會(huì)覆蓋狀態(tài)代碼, headers 可以是一個(gè)列表或字典,作 為額外的消息標(biāo)頭值。

@app.route(‘/demo1’) def demo1():

return ‘狀態(tài)碼為 666’, 666

return ‘狀態(tài)碼為 666’, 666,[(‘itbaizhan’, ‘Python’)]

return ‘狀態(tài)碼為 666’, 666, {‘itbaizhan’: ‘Python’}

響應(yīng)-自定義響應(yīng)

創(chuàng)建Response

from flask import Response @app.route(‘/return_str’) def return_str(): return Response(“你好,少年”)

make_response方式

@app.route(‘/demo2’) def demo2(): resp = make_response(‘make response測(cè)試’) resp.headers[‘itbaizhan’] = ‘Python’ resp.status = ‘404 not found’ return resp

Flask模板

模板介紹

思考 : 網(wǎng)站如何向客戶端返回一個(gè)漂亮的頁(yè)面呢?

提示 :

漂亮的頁(yè)面需要 html 、 css 、 js .可以把這一堆字段串全都寫到視圖中, 作為 HttpResponse() 的參數(shù),響應(yīng)給客戶端

問題

視圖部分代碼臃腫, 耦合度高這樣定義的字符串是不會(huì)出任何效果和錯(cuò)誤的效果無(wú)法及時(shí)查看.有錯(cuò)也不容易及時(shí)發(fā)現(xiàn)

解決問題

模板 Template

MVT 設(shè)計(jì)模式中的 T , Template

M全拼為Model,與MVC中的M功能相同,負(fù)責(zé)和數(shù)據(jù)庫(kù)交 互,進(jìn)行數(shù)據(jù)處理。

V全拼為View,與MVC中的C功能相同,接收請(qǐng)求,進(jìn)行業(yè)務(wù)處 理,返回應(yīng)答。

T全拼為Template,與MVC中的V功能相同,負(fù)責(zé)封裝構(gòu)造要返 回的html。

模板的使用

在 Flask中,配套的模板是 Jinja2,Jinja2的作者也是Flask的作者。 這個(gè)模板非常的強(qiáng)大,并且執(zhí)行效率高。

使用步驟

創(chuàng)建模板

在 應(yīng)用 同級(jí)目錄下創(chuàng)建模板文件夾 templates . 文件夾名稱固定寫法.在 templates 文件夾下, 創(chuàng)建 應(yīng)用 同名文件夾. 例, Book在 應(yīng)用 同名文件夾下創(chuàng)建 網(wǎng)頁(yè)模板 文件. 例 : index.html

設(shè)置模板查找路徑模板處理數(shù)據(jù)

from flask import Flask,render_template app = Flask(name) @app.route(‘/test’) def index(): return render_template(‘index.html’)

模板-傳參

在使用 render_template 渲染模版的時(shí)候,可以傳遞關(guān)鍵字參數(shù)(命名參 數(shù))。

from flask import Flask,render_template app = Flask(name) @app.route(‘/’) def hello_world(): return render_template(‘index.html’,uname=‘sxt’)

SXT 從模版中渲染的數(shù)據(jù)

{{ uname}}

小技巧

如果你的參數(shù)項(xiàng)過多,那么可以將所有的參數(shù)放到一個(gè)字典 中, 然后在傳這個(gè)字典參數(shù)的時(shí)候,使用兩個(gè)星號(hào),將字典打散成 關(guān)鍵字參數(shù)(也叫命名參數(shù))

@app.route(‘/’) def hello_world(): context = { ‘uname’: ‘momo’, ‘a(chǎn)ge’: 18, ‘country’: ‘china’, ‘childrens’: { ‘name’: ‘mjz’, ‘height’: ‘62cm’ } } returnrender_template(‘index.html’,**context)

獲取方式是: {{childrens.name}} 或者 {{childrens[‘name’]}}

模板使用url_for函數(shù)

模版中也可使用 url_for ,和后臺(tái)視圖函數(shù)中的 url_for 使用起來(lái)基本是一 模一樣的。

提示 在模板中使用函數(shù),需要在函數(shù) 左右兩邊加上2個(gè) {} 例如: {{ url_for(func) }}

@app.route(‘/accounts/login//’) def login(name): print(name) return ‘通過URL_FOR定位過來(lái)的?。?!’

登錄

注意 無(wú)論是 路徑參數(shù) 還是 查詢式參數(shù) 都可以直接傳遞

過濾器介紹

有時(shí)候我們想要在模版中對(duì)一些變量進(jìn)行處理,那么就必須需要類 似于Python中的函數(shù)一樣,可以將這個(gè)值傳到函數(shù)中,然后做一些 操作。 在模版中,過濾器相當(dāng)于是一個(gè)函數(shù),把當(dāng)前的變量傳入到過濾器 中,然后過濾器根據(jù)自己的功能,再返回相應(yīng)的值,之后再將結(jié)果 渲染到頁(yè)面中

@app.route(‘/’) def hello_world(): return render_template(‘index.html’,postion=-1)

SXT

過濾器的基本使用

位置的絕對(duì)值為[未使用過濾器]:{{ postion}}

位置的絕對(duì)值為[使用過濾器]:{{ postion|abs}}

Jinja模板自帶過濾器

過濾器是通過管道符號(hào) | 使用的,例如: { name|length }} 將返回name的 長(zhǎng)度。 過濾器相當(dāng)于是一個(gè)函數(shù),把當(dāng)前的變量傳入到過濾器中,然后過 濾器根據(jù)自己的功能,再返回相應(yīng)的值,之后再將結(jié)果渲染到頁(yè)面 中。 Jinja2中內(nèi)置了許多過濾器 https://jinja.palletsprojects.com/en/3.0.x/templates/#filters

defalut過濾器

default過濾器 過濾前的昵稱數(shù)據(jù)是:{{nick_name}}

過濾后的昵稱數(shù)據(jù)是:{{nick_name | default('用戶1',boolean=true)}}

過濾后的昵稱數(shù)據(jù)是:{{nick_name or '用戶2'}}

轉(zhuǎn)義字符

轉(zhuǎn)義字符過濾器

轉(zhuǎn)義前的數(shù)據(jù)是:{{ info | safe }}

{% autoescape true %}

{{info }}

{% endautoescape %}

其它過濾器

其它過濾器 絕對(duì)值:{{ -6 | abs }}

小數(shù): {{ 6 | float }}

字符串:{{ 6 | string }}

格式化:{{'%s--%s' | format('我' , '你')}}

長(zhǎng)度:{{'我是九,你是三,除了你,還是你'|length}}

最后一個(gè):{{'我是九,你是三,除了你,還是你'|last}}

第一個(gè):{{'我是九,你是三,除了你,還是你'|first}}

統(tǒng)計(jì)次數(shù): {{'我是九,你是三,除了你,還是你' | wordcount }}

替換:{{'===我是九,你是三,除了你,還是你 ====' |replace('我是九,你是三,除了你,還是 你' ,'拿著,這個(gè)無(wú)限額度的黑卡,隨便刷')}}

小提示

jinja2模板 默認(rèn)全局開啟了自動(dòng)轉(zhuǎn)義功能

safe 過濾器:可以關(guān)閉一個(gè)字符串的自動(dòng)轉(zhuǎn)義escape 過濾器:對(duì)某一個(gè)字符串進(jìn)行轉(zhuǎn)義autoescape 標(biāo)簽,可以對(duì)他包含的代碼塊關(guān)閉或開啟自動(dòng)轉(zhuǎn)義

{% autoescape true/false %} 代碼塊 {% endautoescape %

自定義過濾器

只有當(dāng)系統(tǒng)提供的過濾器不符合需求后,才須自定義過濾器 過濾器本質(zhì)上就是一個(gè)函數(shù)。 如果在模版中調(diào)用這個(gè)過濾器,那么就會(huì)將這個(gè)變量的值作為第一 個(gè)參數(shù)傳給過濾器這個(gè)函數(shù), 然后函數(shù)的返回值會(huì)作為這個(gè)過濾器的返回值。 需要使用到一個(gè)裝飾器: @app.template_filter(‘過濾器名稱’)

自定義數(shù)據(jù)替換過濾器

例如:將新聞中出現(xiàn)的 所有“ 我是九你是三,除了你還是你” 換成 “你不用多好,我喜歡就好”

#將模版設(shè)置為自動(dòng)加載模式 app.config[‘TEMPLATES_AUTO_RELOAD’]=True @app.template_filter(‘cut’) def cut(value): value=value.replace(“我是九你是三,除了你還是你”,‘你不用多好,我喜歡就好’) return value

使用自定義過濾器:{{新聞內(nèi)容值|cut}}

自定義時(shí)間過濾器

例如:操作發(fā)布新聞 與現(xiàn)在的時(shí)間間隔

from datetime import datetime #需求:操作發(fā)布新聞 與現(xiàn)在的時(shí)間間隔 @app.template_filter(‘handle_time’) def handle_time(time): “”" time距離現(xiàn)在的時(shí)間間隔

如果時(shí)間間隔小于1分鐘以內(nèi),那么就顯示“剛剛”如果是大于1分鐘小于1小時(shí),那么就顯示“xx分鐘前”如果是大于1小時(shí)小于24小時(shí),那么就顯示“xx小時(shí)前”如果是大于24小時(shí)小于30天以內(nèi),那么就顯示“xx天前”否則就是顯示具體的時(shí)間 2030/10/2016:15 “”" if isinstance(time, datetime): now = datetime.now() timestamp = (now - time).total_seconds() if timestamp < 60: return “剛剛” elif timestamp >= 60 and timestamp < 60 * 60: minutes = timestamp / 60 return “%s分鐘前” % int(minutes) elif timestamp >= 60 * 60 and timestamp < 60 * 60 * 24: hours = timestamp / (60 * 60) return ‘%s小時(shí)前’ % int(hours) elif timestamp >= 60 * 60 * 24 and timestamp < 60 * 60 * 24 * 30: days = timestamp / (60 * 60 * 24) return “%s天前” % int(days) else: return time.strftime(‘%Y/%m/%d %H:%M’) else: return time

發(fā)布時(shí)間:{{新聞創(chuàng)建時(shí)間|handle_time}}

流程控制-選擇結(jié)構(gòu)

所有的控制語(yǔ)句都是放在 {% … %} 中,并且有一個(gè)語(yǔ)句 {% endxxx %} 來(lái)進(jìn) 行結(jié)束!

**if:**if語(yǔ)句和python中的類似,可以使用 >,=,==,!= 來(lái)進(jìn)行判 斷,也可以通過 and,or,not,() 來(lái)進(jìn)行邏輯合并操作

{% if age >= 18 %}

{{ age }}歲,成年人,可以通宵打游戲 {% else %}

{{ age }}歲,未成年人,可以通宵學(xué)習(xí) {% endif %}

注意:

if 條件判斷語(yǔ)句必須放在 {% if statement %} 中間,并且還必須有結(jié)束 的標(biāo)簽 {% endif %} 。

流程控制-循環(huán)結(jié)構(gòu)

for…in… for循環(huán)可以遍歷任何一個(gè)序列包括列表、字典、元組。并且 可以進(jìn)行反向遍歷,以下將用幾個(gè)例子進(jìn)行解釋:

列表

{% for user in users%}

{{ user}} {% endfor %}

遍歷字典 {% for key in person.keys() %} {{ key}} {% endfor %} {% for val in person.values() %} {{ val}} {% endfor %} {% for item in person.items() %} {{ item}} {% endfor %} {% for key,value in person.items() %} {{ value}} {% endfor %}

如果序列中沒有值的時(shí)候,進(jìn)入else 反向遍歷用過濾器 reverse:

{% for user in users|reverse %}

{{ user}} {% else %}

沒有任何用戶 {% endfor %}

并且Jinja中的for循環(huán)還包含以下變量,可以用來(lái)獲取當(dāng)前的遍歷狀 態(tài):

總結(jié)

在 jinja2 中的 for 循環(huán),跟 python 中的 for 循環(huán)基本上是一模一樣的 也是 for…in… 的形式。并且也可以遍歷所有的序列以及迭代器 唯一不同的是, jinja2 中的 for 循環(huán)沒有 break 和 continue 語(yǔ)句

導(dǎo)入模板include

這個(gè)標(biāo)簽相當(dāng)于是直接將指定的模版中的代碼復(fù)制粘貼到當(dāng)前位 置。 include 標(biāo)簽,如果想要使用父模版中的變量,直接用就可以了,不 需要使用 with context 。 include 的路徑,也是跟 import 一樣,直接從 templates 根目錄下去找, 不要以相對(duì)路徑去找。

SXT

{% include "common/head.html" %}

這是首頁(yè)內(nèi)容 {{ major }}

{% include "common/footer.html" %}

set與with標(biāo)簽

set的使用

在模版中,可以使用 set 語(yǔ)句來(lái)定義變量

{% set uname=‘sxt’%}

用戶名:{{ uname }}

一旦定義了這個(gè)變量,那么在后面的代碼中,都可以使用這個(gè)變 量,就類似于Python的變量定義是一樣的

with語(yǔ)句

with 語(yǔ)句定義的變量,只能在 with 語(yǔ)句塊中使用,超過了這個(gè)代碼 塊,就不能再使用了

{% with classroom=‘python202’%}

班級(jí):{{ classroom }} {% endwith %}

注意

關(guān)于定義的變量, with 語(yǔ)句也不一定要跟一個(gè)變量, 可以定義一個(gè)空的 with 語(yǔ)句, 需要在指定的區(qū)域才能使用的情況,可以set與with組合使用。

{% with %} {% set pname=‘李思思’ %}

娛樂縣縣長(zhǎng):{{ pname }} {% endwith %}

靜態(tài)文件

靜態(tài)文件:css文件 js文件 圖片文件等文件

加載靜態(tài)文件使用的是 url_for 函數(shù)。然后第一個(gè)參數(shù)需要為 static ,第 二個(gè)參數(shù)需要為一個(gè)關(guān)鍵字參數(shù) filename=‘路徑’ 。

語(yǔ)法

{{ url_for(“static”,filename=‘xxx’) }}

注意 路徑查找,要以當(dāng)前項(xiàng)目的 static 目錄作為根目錄

模板繼承

為什么需要模版繼承

模版繼承可以把一些公用的代碼單獨(dú)抽取出來(lái)放到一個(gè)父模板中 以后子模板直接繼承就可以使用了。 這樣可以重復(fù)的利用代碼,并且以后修改起來(lái)也比較方便

模版繼承語(yǔ)法

使用 extends 語(yǔ)句,來(lái)指明繼承的父模板。父模板的路徑,也是相對(duì) 于 templates 文件夾下的絕對(duì)路徑

{% extends “base.html” %}

block語(yǔ)法

一般在父模版中,定義一些公共的代碼。子模板可能要根據(jù)具體的 需求實(shí)現(xiàn)不同的代碼。這時(shí)候父模版就應(yīng)該有能力提供一個(gè)接口,讓子模板來(lái)實(shí)現(xiàn)。從而 實(shí)現(xiàn)具體業(yè)務(wù)需求的功能。

父模板

{% block block的名字 %} {% endblock %}

子模板

{% block block的名字 %} 子模板中的代碼 {% endblock %}

調(diào)用父模版代碼block中的代碼

默認(rèn)情況下,子模板如果實(shí)現(xiàn)了父模版定義的block。那么子模板 block中的代碼就會(huì)覆蓋掉父模板中的代碼。 如果想要在子模板中仍然保持父模板中的代碼,那么可以使用 {{ super( ) }} 來(lái)實(shí)現(xiàn)

父模板

{% block block_body %}

我是父模版block_body處的內(nèi)容 {% endblock %}

子模板

{% block block_body%} {{ super() }}

我是子模版block_body處的內(nèi)容 {% endblock %}

調(diào)用另外一個(gè)block中的代碼

如果想要在另外一個(gè)模版中使用其他模版中的代碼。那么可以通過 {{ self.其他block名字() }} 就可以了

{% block title %} sxt首頁(yè) {% endblock %} {% block block_body%} {{ self.title() }}

我是子模版block_body處的內(nèi)容 {% endblock %}

注意

子模板中的代碼,第一行,應(yīng)該是 extends 子模板中,如果要實(shí)現(xiàn)自己的代碼,應(yīng)該放到block中。如果 放到其他地方,那么就不會(huì)被渲染

Flask視圖

add_url_rule與app.route

add_url_rule

add_url_rule(rule,endpoint=None,view_func=None)

這個(gè)方法用來(lái)添加url與視圖函數(shù)的映射。 如果沒有填寫 endpoint ,那么默認(rèn)會(huì)使用 view_func 的名字作為 endpoint 。 以后在使用 url_for 的時(shí)候,就要看在映射的時(shí)候有沒有傳遞 endpoint 參 數(shù),如果傳遞了,那么就應(yīng)該使用 endpoint 指定的字符串, 如果沒有傳遞,那么就應(yīng)該使用 view_func 的名字。

def my_list(): return “我是列表頁(yè)” app.add_url_rule(‘/list/’,endpoint=‘sxt’,view_func=my_list)

app.route原理剖析

這個(gè)裝飾器底層,其實(shí)也是使用 add_url_rule 來(lái)實(shí)現(xiàn)url與視圖函數(shù)映射 的。

from flask import Flask,url_for app = Flask(name) @app.route(‘/’,endpoint=‘index’) def index(): print(url_for(‘show’)) print(url_for(‘index’)) return “Hello” def show_me(): return “這個(gè)介紹信息!!”

endpoint 沒有設(shè)置,url_for中就寫函數(shù)的名字,如果設(shè)置了,就寫endpoint的值

app.add_url_rule(‘/show_me’,view_func=show_me,endpoint=‘show’)

@app.route 底層就是使用的 add_url_rule

if name ==‘main’: app.run(debug=True)

類視圖

之前我們接觸的視圖都是函數(shù),所以一般簡(jiǎn)稱函數(shù)視圖。 其實(shí)視圖也可以基于類來(lái)實(shí)現(xiàn),類視圖的好處是支持繼承, 但是類視圖不能跟函數(shù)視圖一樣,寫完類視圖還需要通過 app.add_url_rule(url_rule,view_func) 來(lái)進(jìn)行注冊(cè)

標(biāo)準(zhǔn)類視圖使用步驟

標(biāo)準(zhǔn)類視圖,必須繼承自 flask.views.View 必須實(shí)現(xiàn) dispatch_request 方法,以后請(qǐng)求過來(lái)后,都會(huì)執(zhí)行這個(gè)方 法。 這個(gè)方法的返回值就相當(dāng)于是之前的視圖函數(shù)一樣。也必須返回 Response 或者子類的對(duì)象,或者是字符串,或者是元組。 必須通過 app.add_url_rule(rule,endpoint,view_func) 來(lái)做url與視圖的映射。 view_func 這個(gè)參數(shù),需要使用類視圖下的 as_view 類方法類轉(zhuǎn)換: ListView.as_view(‘list’) 。 如果指定了 endpoint ,那么在使用 url_for 反轉(zhuǎn)的時(shí)候就必須使用 endpoint 指定的那個(gè)值。如果沒有指定 endpoint ,那么就可以使用 as_view(視圖名字) 中指定的視圖名字來(lái)作為反轉(zhuǎn)。

from flask import Flask,url_for from flask.views import View app= Flask(name) @app.route(‘/’) def index():

print(url_for(‘mylist’))

print(url_for(‘my’)) return ‘Hello’ class ListView(View): def dispatch_request(self): return ‘返回了一個(gè)List的內(nèi)容??!’

app.add_url_rule(‘/list’,view_func=ListView.as_view(‘mylist’))

app.add_url_rule(‘/list’,endpoint=‘my’,view_func=ListView.as_view(‘mylist’))

用于測(cè)試

with app.test_request_context(): print(url_for(‘my’)) if name ==‘main’: app.run(debug=True)

類視圖的好處

1.可以繼承,把一些共性的東西抽取出來(lái)放到父視圖中,子視圖直 接拿來(lái)用就可以了。

2.但是也不是說所有的視圖都要使用類視圖,這個(gè)要根據(jù)情況而 定。視圖函數(shù)用得最多。

from flask import Flask,jsonify from flask.views import View app = Flask(name)

需求:返回的結(jié)果都必須是json數(shù)據(jù)

class BaseView(View): def get_data(self): raise NotImplementedError

def dispatch_request(self): return jsonify(self.get_data()) class JsonView(BaseView): def get_data(self): return {‘uname’:‘呂布’,‘a(chǎn)ge’:20} class Json2View(BaseView): def get_data(self): return [ {‘name’:‘zs’,‘lua’:‘Python’}, {‘name’:‘lisi’,‘lua’:‘Python’}, ] app.add_url_rule(‘/base’,view_func=BaseView.as_view(‘base’)) app.add_url_rule(‘/json’,view_func=JsonView.as_view(‘json’)) app.add_url_rule(‘/json2’,view_func=Json2View.as_view(‘json2’)) if name ==‘main’: app.run(debug=True)

基于調(diào)度方法的類視圖

基于方法的類視圖,是根據(jù)請(qǐng)求的 method 來(lái)執(zhí)行不同的方法的。 如果用戶是發(fā)送的 get 請(qǐng)求,那么將會(huì)執(zhí)行這個(gè)類的 get 方法。 如果用戶發(fā)送的是 post 請(qǐng)求,那么將會(huì)執(zhí)行這個(gè)類的 post 方法。其他 的method類似,比如 delete 、 put 這種方式,可以讓代碼更加簡(jiǎn)潔。所有和 get 請(qǐng)求相關(guān)的代碼都放 在 get 方法中,所有和 post 請(qǐng)求相關(guān)的代碼都放在 post 方法中。就不 需要跟之前的函數(shù)一樣,通過 request.method == ‘GET’

class LoginView(views.MethodView): def get(self,error=None): return render_template(‘login.html’,error=error) def post(self): #模擬實(shí)現(xiàn) #拿到前端頁(yè)面?zhèn)鬟^來(lái)的 賬號(hào) 和密碼 去數(shù)據(jù)庫(kù)做查詢操作 查詢到 (跳轉(zhuǎn)主頁(yè)面) ,反之跳轉(zhuǎn)到login.html頁(yè)面并給出錯(cuò)誤提示信息 uname = request.form[‘uname’] pwd = request.form[‘pwd’] if uname==“sxt” and pwd ==“123”: return render_template(‘index.html’) else: return self.get(error=“用戶名或者密碼錯(cuò)誤”)

注冊(cè)類視圖

app.add_url_rule(‘/login/’,view_func=LoginVi ew.as_view(‘my_login’))

HTML

賬號(hào):密碼: {# {{ error }}#} {# 優(yōu)化寫法 :判斷 #} {% if error %} {{ error }} {% endif %}

裝飾器

簡(jiǎn)言之,python裝飾器就是用于拓展原來(lái)函數(shù)功能的一種函數(shù),這 個(gè)函數(shù)的特殊之處在于它的返回值也是一個(gè)函數(shù), 使用python裝飾器的好處就是在不用更改原函數(shù)的代碼前提下給函 數(shù)增加新的功能。

在視圖函數(shù)中使用自定義裝飾器,那么自己定義的裝飾器必須放 在 app.route 下面。 否則這個(gè)裝飾器就起不到任何作用。

案例1

需求:查看設(shè)置個(gè)人信息時(shí),只有檢測(cè)到用戶已經(jīng)登錄了才能查 看,若沒有登錄,則無(wú)法查看并給出提示信息

定義裝飾器

def login_required(func): @wraps(func) def wrapper(*arg,**kwargs): uname = request.args.get(‘uname’) pwd = request.args.get(‘pwd’) if uname == ‘zs’ and pwd == ‘123’: logging.info(f’{uname}:登錄成功’) return func(*arg,**kwargs) else: logging.info(f’{uname}:嘗試登錄,但沒成功’) return ‘請(qǐng)先登錄’ return wrapper

使用裝飾器

@app.route(‘/settings/’) @login_requierd def settings(): return ‘這是設(shè)置界面’

在類視圖中使用裝飾器,需要重寫類視圖的一個(gè)類屬性 decorators , 這個(gè)類屬性是一個(gè)列表或者元組都可以,里面裝的就是所有的裝飾 器。

案例2

需求: 查看設(shè)置個(gè)人信息時(shí),只有檢測(cè)到用戶已經(jīng)登錄了才能查看, 若沒有登錄,則無(wú)法查看并給出提示信息

使用裝飾器

class ProfileView(views.View): decorators = [login_requierd] def dispatch_request(self): return ‘這是個(gè)人中心界面’

app.add_url_rule(‘/profile/’,view_func=ProfileView.as_view(‘profile’))

藍(lán)圖介紹

在Flask中,使用藍(lán)圖Blueprint來(lái)分模塊組織管理。 藍(lán)圖實(shí)際可以理解為是存儲(chǔ)一組視圖方法的容器對(duì)象,其具有如下 特點(diǎn):

一個(gè)應(yīng)用可以具有多個(gè)Blueprint可以將一個(gè)Blueprint注冊(cè)到任何一個(gè)未使用的URL下比如 “/user” 、 “/goods”Blueprint可以單獨(dú)具有自己的模板、靜態(tài)文件或者其它的通用操作方法,它并不是必須要實(shí)現(xiàn)應(yīng) 用的視圖和函數(shù)的在一個(gè)應(yīng)用初始化時(shí),就應(yīng)該要注冊(cè)需要使用的Blueprint

注意

Blueprint并不是一個(gè)完整的應(yīng)用,它不能獨(dú)立于應(yīng)用運(yùn)行,而 必須要注冊(cè)到某一個(gè)應(yīng)用中

使用方式

使用藍(lán)圖可以分為三個(gè)步驟

1 創(chuàng)建一個(gè)藍(lán)圖對(duì)象

user_bp=Blueprint(‘user’,name)

在這個(gè)藍(lán)圖對(duì)象上,

@user_bp.route(‘/’) def user_profile(): return ‘user_profile’

在應(yīng)用對(duì)象上注冊(cè)這個(gè)藍(lán)圖對(duì)象

app.register_blueprint(user_bp)

指定藍(lán)圖的url前綴

在應(yīng)用中注冊(cè)藍(lán)圖時(shí)使用 url_prefix 參數(shù)指定

app.register_blueprint(user_bp,url_prefix=‘/user’) app.register_blueprint(goods_bp,url_prefix=‘/goods’)

藍(lán)圖的目錄結(jié)構(gòu)

為了讓項(xiàng)目代碼更加清晰,可以通過將代碼分在不同的文件里進(jìn)行 管理

根據(jù)功能模塊

對(duì)于一個(gè)打算包含多個(gè)文件的藍(lán)圖,通常將創(chuàng)建藍(lán)圖對(duì)象放到 Python包的 __init__.py 文件中

--------- project # 工程目錄 |------ main.py # 啟動(dòng)文件 |------ user #用戶藍(lán)圖 | |— init.py # 此處創(chuàng)建藍(lán)圖對(duì)象 | |— view.py | |— … |------ goods # 商品藍(lán)圖 | |— init.py | |— … |…

根據(jù)技術(shù)模塊

--------- project # 工程目錄 |------ main.py # 啟動(dòng)文件 |------ view #用戶藍(lán)圖 | |— user.py # 此處創(chuàng)建藍(lán)圖對(duì)象 | |— item.py | |— view.py | |— … |…

藍(lán)圖中模版文件

尋找規(guī)則

如果項(xiàng)目中的templates文件夾中有相應(yīng)的模版文件,就直接使 用了。如果項(xiàng)目中的templates文件夾中沒有相應(yīng)的模版文件,那么就 到在定義藍(lán)圖的時(shí)候指定的路徑中尋找。

并且藍(lán)圖中指定的路徑可以為相對(duì)路徑,相對(duì)的是當(dāng)前這個(gè)藍(lán)圖文件所在的目錄

因?yàn)檫@個(gè)藍(lán)圖文件是在user/view.py,那么就會(huì)到blueprints這個(gè) 文件夾下的user_page文件夾中尋找模版文件。

小總結(jié): 常規(guī):藍(lán)圖文件在查找模版文件時(shí),會(huì)以templates為根目錄進(jìn)行 查找

注意

1 個(gè)性化coder喜歡在【創(chuàng)建藍(lán)圖對(duì)象的時(shí)候】 指定 模版文 件的查找路徑,如下 news_bp =Blueprint(‘news’,__name__,url_prefix=‘/news’,template_folder=‘news_page’)2 只有確定templates目錄下沒有對(duì)應(yīng)的 html文件名的時(shí)候, 才會(huì)去藍(lán)圖文件指定的目錄下查找,指定才會(huì)生效3 若templates目錄下,有一個(gè)與藍(lán)圖文件指定的目錄下同名 的一個(gè) html文件時(shí),優(yōu)先走templates目錄下的東西

藍(lán)圖中靜態(tài)文件

藍(lán)圖內(nèi)部靜態(tài)文件 藍(lán)圖對(duì)象創(chuàng)建時(shí)不會(huì)默認(rèn)注冊(cè)靜態(tài)目錄的路由。需要我們?cè)趧?chuàng)建時(shí) 指定 static_folder 參數(shù)。 下面的示例將藍(lán)圖所在目錄下的 static_admin 目錄設(shè)置為靜態(tài)目錄:

user=Blueprint(“user”,name,static_folder=‘user_static’) app.register_blueprint(admin,url_prefix=‘/user’)

也可通過 static_url_path 改變?cè)L問路徑

user =Blueprint(‘user’,name,template_folder=‘user_page’,static_folder=‘user_static’,static_u rl_path=‘/static’) app.register_blueprint(user,url_prefix=‘/user’)

總結(jié) 【掌握】查找方式1:查找靜態(tài)文件時(shí),正常情況下,會(huì)以 static為根目錄進(jìn)行查找 【了解】查找方式2:查找靜態(tài)文件時(shí),非正常情況下,需要用 url_for(‘藍(lán)圖的名字.static’),然后會(huì)去藍(lán)圖對(duì)象在創(chuàng)建時(shí)指定的 靜態(tài)文件夾目錄下 去查找靜態(tài)文件

藍(lán)圖url_for函數(shù)

如果使用藍(lán)圖,那么以后想要反轉(zhuǎn)藍(lán)圖中的視圖函數(shù)為url,就應(yīng)該 在使用url_for的時(shí)候指定這個(gè)藍(lán)圖名字。 app類中、模版中、同一個(gè)藍(lán)圖類中都是如此。否則就找不到這個(gè) endpoint

html文件中

新聞列表 OK寫法 {# 新聞列表 no Ok寫法#}

python文件中

from flask import Blueprint,render_template,url_for user_bp=Blueprint(‘news’,name,url_prefix=‘/user’,template_folder=‘user_page’,static_folder=‘user_static’) @user_bp.route(‘/list/’) def user_list(): #如下寫法:才找得到 url_for(‘藍(lán)圖名稱.方法名’) print(url_for(‘user.user_list’)) #/user/list/ print(url_for(‘user.user_detail’)) #/user/detail/ return render_template(‘user_list.html’) @user_bp.route(‘/detail/’) def user_detail(): return ‘用戶詳情頁(yè)面’

子域名實(shí)現(xiàn)

藍(lán)圖實(shí)現(xiàn)子域名:

使用藍(lán)圖技術(shù)。 在創(chuàng)建藍(lán)圖對(duì)象的時(shí)候,需要傳遞一個(gè) subdomain 參數(shù),來(lái)指定這 個(gè)子域名的前綴。

cms_bp=Blueprint(‘cms’,name,subdomain=‘cms’)

需要在主app文件中,需要配置app.config的SERVER_NAME參 數(shù)。例如:

app.config[‘SERVER_NAME’]=‘baidu.com:5000’

在windows: C:\Windows\System32\drivers\etc 下,找到hosts文件,然后添 加域名與本機(jī)的映射。Linux: /etc/hosts 域名和子域名都需要做映射

注意 ip地址不能有子域名 localhost也不能有子域名

Flask高級(jí)

Flask設(shè)置Cookie

設(shè)置

設(shè)置cookie是在Response的對(duì)象上設(shè)置。 flask.Response 對(duì)象有一個(gè) set_cookie 方法,可以通過這個(gè)方法來(lái)設(shè)置 cookie 信息。

key,value形式設(shè)置信息

from flask import Flask, make_response app = Flask(name) @app.route(‘/cookie’) def set_cookie(): resp = make_response(‘set cookie ok’) resp.set_cookie(‘uname’, ‘itbaizhan’) return resp

查看Cookie

在Chrome瀏覽器中查看cookie的方式:

方式1:借助于 開發(fā)調(diào)式工具進(jìn)行查看

方式2:在Chrome的設(shè)置界面->高級(jí)設(shè)置->內(nèi)容設(shè)置->所有 cookie->找到當(dāng)前域名下的cookie。

from flask import request @app.route(‘/get_cookie’) def get_cookie(): resp = request.cookies.get(‘uname’) return resp

刪除cookie

方式1:通過 Response對(duì)象.delete_cookie ,指定cookie的key,就可以刪 除cookie了。

from flask import request @app.route(‘/delete_cookie’) def delete_cookie(): response = make_response(‘helloworld’) response.delete_cookie(‘uname’) return response

方式2:在客戶端瀏覽器人為的刪除(清除瀏覽器瀏覽歷史記錄 后,很多網(wǎng)站之前免密登錄的都不好使了)

Cookie的有效期

默認(rèn)的過期時(shí)間:如果沒有顯示的指定過期時(shí)間,那么這個(gè)cookie 將會(huì)在瀏覽器關(guān)閉后過期。 max_age:以秒為單位,距離現(xiàn)在多少秒后cookie會(huì)過期。

expires:為datetime類型。這個(gè)時(shí)間需要設(shè)置為格林尼治時(shí)間, 相對(duì)北京時(shí)間來(lái)說 會(huì)自動(dòng)+8小時(shí) 如果max_age和expires都設(shè)置了,那么這時(shí)候以max_age為標(biāo) 準(zhǔn)。

注意

max_age在IE8以下的瀏覽器是不支持的。 expires雖然在新版的HTTP協(xié)議中是被廢棄了,但是到目前為 止,所有的瀏覽器都還是能夠支持,所以如果想要兼容IE8以下 的瀏覽器,那么應(yīng)該使用expires,否則可以使用max_age。

from flask import Flask,Response app = Flask(name) @app.route(‘/’) def index(): return ‘Hello??!’ @app.route(‘/create_cookie/defualt/’) def create_cookie1(): resp = Response(‘通過默認(rèn)值,設(shè)置cookie有效期’)

如果沒有設(shè)置有效期,默認(rèn)會(huì)在瀏覽器關(guān)閉的時(shí)候,讓cookie過期

resp.set_cookie(‘uname’,‘zs’) return resp @app.route(‘/create_cookie/max_age/’) def create_cookie2(): resp = Response(‘通過max_age,設(shè)置cookie有效期’)

max_age以秒為單位設(shè)置cookie的有效期

age = 60602

resp.set_cookie(‘uname’,‘zs’,max_age=age) return resp from datetime import datetime @app.route(‘/create_cookie/expires/’) def create_cookie3(): resp = Response(‘通過expires,設(shè)置cookie有效期’)

expires 以指定時(shí)間為cookie的有效期

16+8 == 24

tmp_time = datetime(2021, 11,11,hour=18,minute=0,second=0)

resp.set_cookie(‘uname’,‘python’,expires=tmp_time) return resp from datetime import timedelta @app.route(‘/create_cookie/expires2/’) def create_cookie4(): resp = Response(‘通過expires,設(shè)置cookie有效期’)

expires 以指定時(shí)間為cookie的有效期

tmp_time = datetime.now() +timedelta(days=2) resp.set_cookie(‘uname’,‘python_sql’,expires=tmp_time) return resp @app.route(‘/create_cookie/exp_max/’) def create_cookie5(): resp = Response(‘通過expires與max_age,設(shè)置cookie有效期’)

expires 與max_age同時(shí)設(shè)置了,會(huì)以max_age為準(zhǔn)

tmp_time = datetime.now() +timedelta(days=2)

resp.set_cookie(‘uname’,‘python_sql’,expires=tmp_time,max_age = 60602) return resp if name == ‘main’: app.run(debug=True)

Flask中使用Session

需要先設(shè)置SECRET_KEY

class DefaultConfig(object): SECRET_KEY = ‘fih9fh9eh9gh2’ app.config.from_object(DefaultConfig)

或者直接設(shè)置

app.secret_key=‘xihwidfw9efw’

設(shè)置、修改

from flask import session @app.route(‘/set_session/’) def set_session(): session[‘username’] = ‘zs’ return ‘set session ok’

讀取

@app.route(‘/get_session/’) def get_session(): username = session.get(‘username’) return ‘get session username {}’.format(username)

刪除

@app.route(‘/del_session/’) def delete_session(): #刪除指定的key的session

session.pop(‘uname’)

#刪除session中的所有的key 【刪除所有】 session.clear() return ‘刪除成功’

Flask設(shè)置Session的有效期

如果沒有設(shè)置session的有效期。那么默認(rèn)就是瀏覽器關(guān)閉后過期。 如果設(shè)置session.permanent=True,那么就會(huì)默認(rèn)在31天后過 期。 如果不想在31天后過期,按如下步驟操作。

1 session.permanent=True

2 可以設(shè)置 app.config[‘PERMANENT_SESSION_LIFETIME’] = timedelta(hour=2) 在兩個(gè)小時(shí)后過期。

from flask import Flask,session from datetime import timedelta app = Flask(name) app.secret_key = ‘sdfdfdsfsss’ app.config[‘PERMANENT_SESSION_LIFETIME’] = timedelta(days=2) @app.route(‘/’) def index(): return ‘Hello??!’ @app.route(‘/set_session/’) def set_session():

設(shè)置session的持久化,默認(rèn)是增加了31天

session.permanent = True session[‘uname’] = ‘10001’ return ‘設(shè)置一個(gè)Session的信息’ @app.route(‘/get_session/’) def get_session():

如果服務(wù)器關(guān)閉掉了,session的有效期,依然是之前系統(tǒng)保存日期

如果secret_key設(shè)置是一個(gè)固定的值,那么服務(wù)器重啟不會(huì)影響session的有效器

如果secret_key設(shè)置不是一個(gè)固定的值,那么服務(wù)器之前設(shè)置的session將全部過期

return session.get(‘uname’) if name == ‘main’: app.run(debug=True)

Session實(shí)戰(zhàn)

login.html

Document

賬號(hào):密碼: {% if msg %} {{ msg }} {% endif %}

from flask import Flask, session, request,redirect,url_for,views,render_template app = Flask(name)

定義一個(gè)基于方法調(diào)度的 類視圖

class LoginView(views.MethodView): def __jump(self,msg=None): return render_template(‘login.html’,msg = msg) def get(self): msg = request.args.get(‘msg’) return self.__jump(msg) def post(self): uname = request.form.get(‘uname’) pwd = request.form.get(‘pwd’) if uname == “zs” and pwd == “123”: session[‘uname’] = uname return render_template(‘index.html’) else: return self.__jump(msg=“用戶名或者密碼錯(cuò)誤”) @app.route(‘/index/’) def index(): uname = session.get(‘uname’) if uname: return ‘這個(gè)是主頁(yè)?。?!’ return redirect(url_for(‘login’,msg=‘請(qǐng)先登錄’))

注冊(cè)類視圖

app.add_url_rule(‘/login/’,view_func=LoginView.as_view(‘login’)) if name == ‘main’: app.secret_key = ‘xihwidfw9efw’ app.run(debug=True)

Local對(duì)象

需求

要實(shí)現(xiàn)并發(fā)效果, 每一個(gè)請(qǐng)求進(jìn)來(lái)的時(shí)候我們都開啟一個(gè)進(jìn)程, 這顯然是不合理的, 于是就可以使用 線程 那么線程中數(shù)據(jù)互相不隔離,存在修改數(shù)據(jù)的時(shí)候數(shù)據(jù)不安全的問題

Local對(duì)象

在Flask中,類似于 request 對(duì)象,其實(shí)是綁定到了一個(gè) werkzeug.local.Local 對(duì)象上。 這樣,即使是同一個(gè)對(duì)象,那么在多個(gè)線程中都是隔離的。類似的 對(duì)象還有 session 對(duì)象。

ThreadLocal變量

Python提供了ThreadLocal 變量,它本身是一個(gè)全局變量, 但是每個(gè)線程卻可以利用它來(lái)保存屬于自己的私有數(shù)據(jù), 這些私有數(shù)據(jù)對(duì)其他線程也是不可見的。

from threading import Thread,local local =local() local.request = ‘具體用戶的請(qǐng)求對(duì)象’ class MyThread(Thread): def run(self): local.request = ‘zs’ print(‘子線程:’,local.request) mythread = MyThread() mythread.start() mythread.join() print(‘主線程:’,local.request)

from werkzeug.local import Local local = Local() local.request = ‘具體用戶的請(qǐng)求對(duì)象’ class MyThread(Thread): def run(self): local.request = ‘sxt’ print(‘子線程:’,local.request) mythread = MyThread() mythread.start() mythread.join() print(‘主線程:’,local.request)

總結(jié)

只要滿足綁定到"local"或"Local"對(duì)象上的屬性,在每個(gè)線程中都是 隔離的,那么他就叫做 ThreadLocal 對(duì)象,也叫’ThreadLocal’變量。

Flask_app上下文

App上下文,也叫應(yīng)用上下文

上下文(感性的理解)

每一段程序都有很多外部變量,只有像add這種簡(jiǎn)單的函數(shù)才是 沒有外部變量的。 一旦一段程序有了外部變量,這段程序就不 完整,不能獨(dú)立運(yùn)行。為了能讓這段程序可以運(yùn)行,就要給所 有的外部變量一個(gè)一個(gè)設(shè)置一些值。就些值所在的集合就是叫 上下文。 并且上下文這一概念在中斷任務(wù)的場(chǎng)景下具有重大意義,其中 任務(wù)在被中斷后,處理器保存上下文并提供中斷處理,因些在 這之后,任務(wù)可以在同一個(gè)地方繼續(xù)執(zhí)行。(上下文越小,延遲 越小)

舉例

運(yùn)行的Flask項(xiàng)目,每一個(gè)路由映射的內(nèi)容片段,都不可以單獨(dú) 拿出來(lái)使用.

當(dāng)獲取到了APP_Context以后,就可以直接通過程序映射的地 址訪問邏輯,并且可以重復(fù)使用。

上下文的一個(gè)典型應(yīng)用場(chǎng)景就是用來(lái)緩存一些我們需要在發(fā)生請(qǐng)求 之前或者要使用的資源。舉個(gè)例子,比如數(shù)據(jù)庫(kù)連接。當(dāng)我們?cè)趹?yīng) 用上下文中來(lái)存儲(chǔ)東西的時(shí)候你得選擇一個(gè)唯一的名字,這是因?yàn)?應(yīng)用上下文為 Flask 應(yīng)用和擴(kuò)展所共享。

應(yīng)用上下文:

應(yīng)用上下文是存放到一個(gè) LocalStack 的棧中。和應(yīng)用app相關(guān)的操作就 必須要用到應(yīng)用上下文

比如:

通過 current_app 獲取當(dāng)前的這個(gè) app 名字。

注意

在視圖函數(shù)中,不用擔(dān)心應(yīng)用上下文的問題。因?yàn)橐晥D函數(shù)要 執(zhí)行,那么肯定是通過訪問url的方式執(zhí)行的, 那么這種情況下,F(xiàn)lask底層就已經(jīng)自動(dòng)的幫我們把應(yīng)用上下文 都推入到了相應(yīng)的棧中。

如果想要在視圖函數(shù)外面執(zhí)行相關(guān)的操作, 比如: 獲取當(dāng)前的app名稱,那么就必須要手動(dòng)推入應(yīng)用上下文

第一種方式:便于理解的寫法

from flask import Flask,current_app app = Flask(name) #app上下文 app_context = app.app_context() app_context.push() print(current_app.name) @app.route(‘/’) def hello_world(): print(current_app.name) #獲取應(yīng)用的名稱 return ‘Hello World!’ if name == ‘main’: app.run(debug=True)

第二種方式:用with語(yǔ)句

from flask import Flask,current_app app = Flask(name) #app上下文 #換一種寫法 with app.app_context(): print(current_app.name) @app.route(‘/’) def hello_world(): print(current_app.name) #獲取應(yīng)用的名稱 return ‘Hello World!’ if name == ‘main’: app.run(debug=True)

Flask_線程隔離的g對(duì)象

保存為全局對(duì)象g對(duì)象的好處:

g對(duì)象是在整個(gè)Flask應(yīng)用運(yùn)行期間都是可以使用的。 并且也跟request一樣,是線程隔離的。 這個(gè)對(duì)象是專門用來(lái)存儲(chǔ)開發(fā)者自己定義的一些數(shù)據(jù),方便在整個(gè) Flask程序中都可以使用。 一般使用就是,將一些經(jīng)常會(huì)用到的數(shù)據(jù)綁定到上面,以后就直接 從g上面取就可以了,而不需要通過傳參的形式,這樣更加方便。

g對(duì)象使用場(chǎng)景:

有一個(gè)工具類utils.py 和 用戶辦理業(yè)務(wù):

def funa(uname): print(f’funa {uname}‘) def funb(uname): print(f’funb {uname}’) def func(uname): print(f’func {uname}')

用戶辦理業(yè)務(wù)

from flask import Flask,request from utils import funa,funb,func app = Flask(name) #Flask_線程隔離的g對(duì)象使用詳解 @app.route(“/profile/”) def my_profile(): #從url中取參 uname = request.args.get(‘uname’) #調(diào)用功能函數(shù)辦理業(yè)務(wù) funa(uname) funb(uname) func(uname) #每次都得傳參 麻煩,引入g對(duì)象進(jìn)行優(yōu)化 return “辦理業(yè)務(wù)成功” if name == ‘main’: app.run(debug=True)

優(yōu)化工具類utils.py

from flask import g def funa(): print(f’funa {g.uname}‘) def funb(): print(f’funb {g.uname}’) def func(): print(f’func {g.uname}')

Flask_鉤子函數(shù)介紹

鉤子函數(shù)概念

在Flask中鉤子函數(shù)是使用特定的裝飾器裝飾的函數(shù)。 為什么叫做鉤子函數(shù)呢,是因?yàn)殂^子函數(shù)可以在正常執(zhí)行的代碼 中,插入一段自己想要執(zhí)行的代碼。 那么這種函數(shù)就叫做鉤子函數(shù)。

常見的鉤子函數(shù)

before_first_request:處理項(xiàng)目的第一次請(qǐng)求之前執(zhí)行。

@app.before_first_request def first_request(): print(‘first time request’)

before_request:在每次請(qǐng)求之前執(zhí)行。通??梢杂眠@個(gè)裝飾 器來(lái)給視圖函數(shù)增加一些變量。請(qǐng)求已經(jīng)到達(dá)了Flask,但是還 沒有進(jìn)入到具體的視圖函數(shù)之前調(diào)用。一般這個(gè)就是在視圖函數(shù) 之前,我們可以把一些后面需要用到的數(shù)據(jù)先處理好,方便視圖 函數(shù)使用。

@app.before_request def before_request(): if not hasattr(g,‘glo1’): setattr(g,‘glo1’,‘想要設(shè)置的’)

teardown_appcontext:不管是否有異常,注冊(cè)的函數(shù)都會(huì)在 每次請(qǐng)求之后執(zhí)行。

@app.teardown_appcontext def teardown(exc=None): if exc is None: db.session.commit() else: db.session.rollback() db.session.remove()

template_filter:在使用Jinja2模板的時(shí)候自定義過濾器。

@app.template_filter(“upper”) def upper_filter(s): return s.upper()

context_processor:上下文處理器。使用這個(gè)鉤子函數(shù),必須 返回一個(gè)字典。這個(gè)字典中的值在所有模版中都可以使用。這個(gè) 鉤子函數(shù)的函數(shù)是,如果一些在很多模版中都要用到的變量,那 么就可以使用這個(gè)鉤子函數(shù)來(lái)返回,而不用在每個(gè)視圖函數(shù)中 的 render_template 中去寫,這樣可以讓代碼更加簡(jiǎn)潔和好維護(hù)。

@app.context_processor def context_processor(): if hasattr(g,‘user’): return {“current_user”:g.user} else: return {}

errorhandler:errorhandler接收狀態(tài)碼,可以自定義返回這 種狀態(tài)碼的響應(yīng)的處理方法。在發(fā)生一些異常的時(shí)候,比如404 錯(cuò)誤,比如500錯(cuò)誤,那么如果想要優(yōu)雅的處理這些錯(cuò)誤,就可以 使用 errorhandler 來(lái)出來(lái)。

@app.errorhandler(404) def page_not_found(error): return ‘This page does not exist’,404

Flask_信號(hào)機(jī)制

信號(hào)機(jī)制

大白話來(lái)說,類似于兩方屬于敵對(duì)關(guān)系時(shí),某人在敵對(duì)方陣營(yíng)進(jìn)行 交談,一旦遇到特殊情況,某人便會(huì)發(fā)送信號(hào),他的同伙接收(監(jiān) 聽)到他發(fā)的信號(hào)后,同伙便會(huì)做出一系列的應(yīng)對(duì)策略(進(jìn)攻|撤 退)。 flask中的信號(hào)使用的是一個(gè)第三方插件,叫做blinker。通過pip list看一下,如果沒有安裝,通過以下命令即可安裝blinker

pip install blinker

自定義信號(hào)步驟

自定義信號(hào)可分為3步來(lái)完成。

第一是創(chuàng)建一個(gè)信號(hào),第二是監(jiān)聽一個(gè)信號(hào),第三是發(fā)送一個(gè)信 號(hào)。

以下將對(duì)這三步進(jìn)行講解:

創(chuàng)建信號(hào):定義信號(hào)需要使用到blinker這個(gè)包的Namespace類來(lái)創(chuàng)建一個(gè)命名空間。比如定義一 個(gè)在訪問了某個(gè)視圖函數(shù)的時(shí)候的信號(hào)。示例代碼如下:

Namespace的作用:為了防止多人開發(fā)的時(shí)候,信號(hào)名字

沖突的問題 from blinker import Namespace mysignal = Namespace() signal1 = mysignal.signal(‘信號(hào)名稱’)

監(jiān)聽信號(hào):監(jiān)聽信號(hào)使用signal1對(duì)象的connect方法,在這個(gè)方法中需要傳遞一個(gè)函數(shù),用來(lái)監(jiān)聽 到這個(gè)信號(hào)后做該做的事情。示例代碼如下:

def func1(sender,uname): print(sender) print(uname) signal1.connect(func1)

發(fā)送信號(hào):發(fā)送信號(hào)使用signal1對(duì)象的send方法,這個(gè)方法可以傳遞一些其他參數(shù)過去。示例代 碼如下:

signal1.send(uname=‘momo’)

Flask信號(hào)使用場(chǎng)景_存儲(chǔ)用戶登錄日志

信號(hào)使用場(chǎng)景

定義一個(gè)登錄的信號(hào),以后用戶登錄進(jìn)來(lái)以后 就發(fā)送一個(gè)登錄信號(hào),然后能夠監(jiān)聽這個(gè)信號(hào) 在監(jiān)聽到這個(gè)信號(hào)以后,就記錄當(dāng)前這個(gè)用戶登錄的信息 用信號(hào)的方式,記錄用戶的登錄信息即登錄日志。

編寫一個(gè)signals.py文件創(chuàng)建登錄信號(hào)

from blinker import Namespace from datetime import datetime from flask import request,g namespace = Namespace() #創(chuàng)建登錄信號(hào) login_signal = namespace.signal(‘login’) def login_log(sender):

用戶名 登錄時(shí)間 ip地址

now = datetime.now() ip = request.remote_addr log_data = “{uname}{now}{ip}”.format(uname=g.uname, now=now, ip=ip) with open(‘login_log.txt’,‘a(chǎn)’) as f: f.write(log_data + “\n”) f.close() #監(jiān)聽信號(hào) login_signal.connect(login_log)

使用信號(hào)存儲(chǔ)用戶登錄日志

from flask import Flask,request,g from signals import login_signal app = Flask(name) @app.route(‘/login/’) def login():

通過查詢字符串的形式來(lái)傳遞uname這個(gè)參數(shù)

uname = request.args.get(‘uname’) if uname: g.uname = uname

發(fā)送信號(hào)

login_signal.send() return ‘登錄成功!’ else: return ‘請(qǐng)輸入用戶名!’ if name == ‘main’: app.run(debug=True)

Flask_內(nèi)置信號(hào)

Flask內(nèi)置了10個(gè)常用的信號(hào):

1 template_rendered:模版渲染完成后的信號(hào)。

2 before_render_template:模版渲染之前的信號(hào)。

3 request_started:請(qǐng)求開始之前,在到達(dá)視圖函數(shù)之前發(fā)送信號(hào)。

4 request_finished:請(qǐng)求結(jié)束時(shí),在響應(yīng)發(fā)送給客戶端之前發(fā)送信號(hào)。

5 request_tearing_down:請(qǐng)求對(duì)象被銷毀時(shí)發(fā)送的信號(hào),即使在請(qǐng)求過程中發(fā)生異常也會(huì)發(fā)送信 號(hào)。

6 got_request_exception:在請(qǐng)求過程中拋出異常時(shí)發(fā)送信號(hào),異常本身會(huì)通過exception傳遞到訂 閱(監(jiān)聽)的函數(shù)中。一般可以監(jiān)聽這個(gè)信號(hào),來(lái)記錄網(wǎng)站異常信息。

7 appcontext_tearing_down:應(yīng)用上下文被銷毀時(shí)發(fā)送的信號(hào)。

8 appcontext_pushed:應(yīng)用上下文被推入到棧上時(shí)發(fā)送的信號(hào)。

9 appcontext_popped:應(yīng)用上下文被推出棧時(shí)發(fā)送的信號(hào)。

10 message_flashed:調(diào)用了Flask的 flash 方法時(shí)發(fā)送的信號(hào)。

WTForms介紹和基本使用

WTForms介紹

這個(gè)插件庫(kù)主要有兩個(gè)作用。 第一個(gè)是做表單驗(yàn)證,將用戶提交上來(lái)的數(shù)據(jù)進(jìn)行驗(yàn)證是否符合系 統(tǒng)要求。 第二個(gè)是做模版渲染。 (了解即可) 官網(wǎng):https://wtforms.readthedocs.io/en/latest/index.html

Flask-WTF是簡(jiǎn)化了WTForms操作的一個(gè)第三方庫(kù)。WTForms表單 的兩個(gè)主要功能是驗(yàn)證用戶提交數(shù)據(jù)的合法性以及渲染模板。而 Flask-WTF還包括一些其他的功能:CSRF保護(hù),文件上傳等。 安裝Flask-WTF默認(rèn)也會(huì)安裝WTForms,因此使用以下命令來(lái)安裝 Flask-WTF和WTForms:

pip install flask-wtf

WTForms表單驗(yàn)證的基本使用

1 自定義一個(gè)表單類,繼承自wtforms.Form類。

2 定義好需要驗(yàn)證的字段,字段的名字必須和模版中那些需要驗(yàn)證的input標(biāo)簽的name屬性值保持一 致。

3 在需要驗(yàn)證的字段上,需要指定好具體的數(shù)據(jù)類型。

4 在相關(guān)的字段上,指定驗(yàn)證器。

5 以后在視圖函數(shù)中,只需要使用這個(gè)表單類的對(duì)象,并且把需要驗(yàn)證的數(shù)據(jù),也就是request.form 傳給這個(gè)表單類,再調(diào)用表單類對(duì)象.validate()方法進(jìn)行,如果返回True,那么代表用戶輸入的數(shù) 據(jù)都是符合格式要求的,F(xiàn)lase則代表用戶輸入的數(shù)據(jù)是有問題的。如果驗(yàn)證失敗了,那么可以通 過表單類對(duì)象.errors來(lái)獲取具體的錯(cuò)誤信息。

from flask import Flask,render_template,request from wtforms import Form,StringField from wtforms.validators import Length,EqualTo app = Flask(name) @app.route(‘/’) def index(): return ‘Hello! ’ class RegisterForm(Form): uname = StringField(validators=[Length(min=2,max=10,message=‘用戶名長(zhǎng)度2-10之間’)]) pwd = StringField(validators=[Length(min=2,max=10)]) pwd2 = StringField(validators=[Length(min=2,max=10),EqualTo(‘pwd’,message=‘2次密碼不一致’)]) @app.route(’/register/‘, methods=[‘GET’,‘POST’]) def register(): if request.method == ‘GET’: return render_template(‘register.html’) else: form = RegisterForm(request.form) if form.validate(): # 驗(yàn)證成功:True,失敗:False return ‘驗(yàn)證成功!’ else: return f’驗(yàn)證失?。form.errors}’ if name == ‘main’: app.run(debug=True)

WTForms常用驗(yàn)證器

頁(yè)面把數(shù)據(jù)提交上來(lái),需要經(jīng)過表單驗(yàn)證,進(jìn)而需要借助驗(yàn)證器來(lái) 進(jìn)行驗(yàn)證,以下是常用的內(nèi)置驗(yàn)證器:

Length:字符串長(zhǎng)度限制,有min和max兩個(gè)值進(jìn)行限制。

username = StringField(validators=[Length(min=3,max=10,message=“用戶名長(zhǎng)度必須在3到10位之間”)])

EqualTo:驗(yàn)證數(shù)據(jù)是否和另外一個(gè)字段相等,常用的就是密碼 和確認(rèn)密碼兩個(gè)字段是否相等。

password_repeat = StringField(validators=[Length(min=6,max=10),EqualTo(“password”)])

Email:驗(yàn)證上傳的數(shù)據(jù)是否為郵箱數(shù)據(jù)格式 如:223333@qq. com。

email = StringField(validators=[Email()])

InputRequired:驗(yàn)證該項(xiàng)數(shù)據(jù)為必填項(xiàng),即要求該項(xiàng)非空。

username = StringField(validators=[input_required()])

NumberRange:數(shù)值的區(qū)間,有min和max兩個(gè)值限制,如果 處在這兩個(gè)數(shù)字之間則滿足。

age = IntegerField(validators=[NumberRange(12,18)])

Regexp:定義正則表達(dá)式進(jìn)行驗(yàn)證,如驗(yàn)證手機(jī)號(hào)碼。

phone = StringField(validators=[Regexp(r’1[34578]\d{9}')])

URL:必須是URL的形式 如http://www.bjsxt.com。

home_page = StringField(validators=[URL()])

UUID:驗(yàn)證數(shù)據(jù)是UUID類型。

uuid = StringField(validators=[UUID()])

WTForms自定義驗(yàn)證器

只有當(dāng)WTForms內(nèi)置的驗(yàn)證器不夠使的時(shí)候,才需要使用自定義驗(yàn) 證器。 如果想要對(duì)表單中的某個(gè)字段進(jìn)行更細(xì)化的驗(yàn)證,那么可以針對(duì)這 個(gè)字段進(jìn)行單獨(dú)的驗(yàn)證。

自定義驗(yàn)證器步驟如下:

1 定義一個(gè)方法,方法的名字規(guī)則是: validate_字段名(self,field) 。

2 在方法中,使用 field.data 可以獲取到這個(gè)字段的具體的值。

3 驗(yàn)證時(shí),如果數(shù)據(jù)滿足條件,那么可以什么都不做。如果驗(yàn)證失敗,那么應(yīng)該拋出一個(gè) wtforms.validators.ValidationError 的異常,并且把驗(yàn)證失敗 的信息傳到這個(gè)異常類中。

場(chǎng)景:驗(yàn)證碼實(shí)現(xiàn)

關(guān)鍵代碼演示:(實(shí)現(xiàn)驗(yàn)證碼 驗(yàn)證)

from flask import session from wtforms import Form,StringField,IntegerField from wtforms.validators import Length,EqualTo,Email,InputRequired,NumberRan ge,Regexp,URL,UUID,ValidationError class RegisterForm2(Form): email = StringField(validators=[Email()]) uname = StringField(validators=[InputRequired()]) age = IntegerField(validators=[NumberRange(18,40)]) phone = StringField(validators=[Regexp(r’1[34578]\d{9}')]) phomepage = StringField(validators=[URL()]) uuid = StringField(validators=[UUID()]) code = StringField(validators=[Length(4,4)]) #取到的值 和服務(wù)器上 session上存儲(chǔ)的值對(duì)比 def validate_code(self,field): print(field.data,session.get(‘code’)) if field.data !=session.get(‘code’): raise ValidationError(‘驗(yàn)證碼不一致!’)

Flask安全上傳文件

上傳文件步驟:

在模版html中,表單需要指定 enctype=‘multipart/form-data’ 才能上傳文 件。 在后臺(tái)如果想要獲取上傳的文件,那么應(yīng)該使用 request.files.get(‘文件 名’) 來(lái)獲取。 保存文件之前,先要使用 werkzeug.utils.secure_filename 來(lái)對(duì)上傳上來(lái)的文 件名進(jìn)行一個(gè)過濾。能保證不會(huì)有安全問題。 獲取到上傳上來(lái)的文件后,使用 文件對(duì)象.save(路徑) 方法來(lái)保存文件。 路徑=完整路徑=路徑名+文件名

upload.html頁(yè)面

上傳文件

頭像:描述:

app.py文件

from flask import Flask,request,render_template import os from werkzeug.utils import secure_filename app = Flask(name) UPLOAD_PATH = os.path.join(os.path.dirname(file),‘images’) @app.route(‘/upload/’,methods=[‘GET’,‘POST’]) def upload(): if request.method == ‘GET’: return render_template(‘upload.html’) else: desc = request.form.get(“desc”) pichead = request.files.get(“pichead”) filename = secure_filename(pichead.filename) #包裝一下 保證文件安全 #pichead.save(os.path.join(UPLOAD_PATH,pichead.filename)) #可優(yōu)化 pichead.save(os.path.join(UPLOAD_PATH,filename)) #已優(yōu)化 print(desc) return ‘文件上傳成功’

if name == ‘main’: app.run(debug=True)

訪問文件

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

from flask import Flask import os from flask import send_from_directory app = Flask(name) UPLOAD_PATH = os.path.join(os.path.dirname(file),‘images’) @app.route(‘/images//’) def get_image(filename): return send_from_directory(UPLOAD_PATH,filename) if name == ‘main’: app.run(debug=True)

利用flask-wtf驗(yàn)證上傳的文件

關(guān)鍵點(diǎn):

1 定義驗(yàn)證表單類的時(shí)候,對(duì)文件類型的字段,需要采用 FileField 這個(gè)類型,即wtforms.FileField 2 驗(yàn)證器需要從 flask_wtf.file 中導(dǎo)入。 flask_wtf.file.FileRequired 和 flask_wtf.file.FileAllowed

3 flask_wtf.file.FileRequired 是用來(lái)驗(yàn)證文件上傳不能為空。

4 flask_wtf.file.FileAllowed 用來(lái)驗(yàn)證上傳的文件的后綴名, 如常見圖片后綴 .jpg 和.png以及.gif等。

5 在視圖函數(shù)中,需要使用 from werkzeug.datastructures import CombinedMultiDict 來(lái)把 request.form 與 request.files 來(lái)進(jìn)行合并。

6 最后使用 表單驗(yàn)證對(duì)象.validate()進(jìn)行驗(yàn)證。

代碼如下:

upload.html頁(yè)面

上傳文件

頭像:描述:

formscheck.py文件

from wtforms import Form,FileField,StringField from wtforms.validators import InputRequired

flask_wtf

from flask_wtf.file import FileRequired,FileAllowed class UploadForm(Form): pichead = FileField(validators= [FileRequired(),FileAllowed([‘jpg’,‘png’,‘gif’])]) desc = StringField(validators=[InputRequired()])

app.py文件

from flask import Flask,request,render_template import os from werkzeug.utils import secure_filename from formscheck import UploadForm from werkzeug.datastructures import CombinedMultiDict app = Flask(name) UPLOAD_PATH = os.path.join(os.path.dirname(file),‘images’) #利用flask-wtf驗(yàn)證上傳的文件 @app.route(‘/upload/’,methods=[‘GET’,‘POST’]) def upload(): if request.method == ‘GET’: return render_template(‘upload.html’) else: form = UploadForm(CombinedMultiDict([request.form,request.files])) if form.validate():

desc = request.form.get(“desc”)

pichead = request.files.get(“pichead”)

desc = form.desc.data pichead = form.pichead.data filename = secure_filename(pichead.filename) pichead.save(os.path.join(UPLOAD_PATH,filename)) print(desc) return ‘文件上傳成功’ else: print(form.errors) return “文件上傳失敗” if name == ‘main’: app.run(debug=True)

Restful介紹

1.Restful接口規(guī)范

REST 指的是一組架構(gòu)約束條件和原則。滿足這些約束條件和原則的 應(yīng)用程序或設(shè)計(jì)就是 RESTful。 RESTful是一種軟件架構(gòu)風(fēng)格、設(shè)計(jì)風(fēng)格,而不是標(biāo)準(zhǔn),只是提供了 一組設(shè)計(jì)原則和約束條件。 它主要用于客戶端和服務(wù)器交互類的軟件?;谶@個(gè)風(fēng)格設(shè)計(jì)的軟 件可以更簡(jiǎn)潔,更有層次。 RESTful接口規(guī)范是用于在前端與后臺(tái)進(jìn)行通信的一套規(guī)范。使用這 個(gè)規(guī)范可以讓前后端開發(fā)變得更加輕松。

**2.適用場(chǎng)景:**一個(gè)系統(tǒng)的數(shù)據(jù)庫(kù)數(shù)據(jù),展現(xiàn)的平臺(tái)有PC端、移動(dòng) 端、app端、ios端。 前端工程師:都遵循RESTful編程規(guī)范 后端工程師:都遵循RESTful編程規(guī)范 最終結(jié)果:開發(fā)效率高,便于管理。

**3.協(xié)議:**用http或者h(yuǎn)ttps協(xié)議。

4.數(shù)據(jù)傳輸格式: 數(shù)據(jù)傳輸?shù)母袷綉?yīng)該都用json格式。

**5.url鏈接規(guī)則:**url鏈接中,不能有動(dòng)詞,只能有名詞。 并且對(duì)于一些名詞,如果出現(xiàn)復(fù)數(shù),那么應(yīng)該在后面加s。 比如:獲取新聞列表,應(yīng)該使用 /news/ ,而不應(yīng)該使用/get_news/

6.HTTP請(qǐng)求方式: GET:從服務(wù)器上獲取資源。 POST:在服務(wù)器上新增或者修改一個(gè)資源。 PUT:在服務(wù)器上更新資源。(客戶端提供所有改變后的數(shù)據(jù)) PATCH:在服務(wù)器上更新資源。(客戶端只提供需要改變的屬性) DELETE:從服務(wù)器上刪除資源。

7.狀態(tài)碼:

Restful的基本使用

1.介紹:

優(yōu)勢(shì): Flask-Restful是一個(gè)專門用來(lái)寫restful api的一個(gè)插件。 使用它可以快速的集成restful api接口功能。 在系統(tǒng)的純api的后臺(tái)中,這個(gè)插件可以幫助我們節(jié)省很多時(shí)間。

缺點(diǎn): 如果在普通的網(wǎng)站中,這個(gè)插件就沒有優(yōu)勢(shì)了,因?yàn)樵谄胀ǖ木W(wǎng)站 開發(fā)中,是需要去渲染HTML代碼的, 而Flask-Restful在每個(gè)請(qǐng)求中都是返回json格式的數(shù)據(jù)。

**2.安裝:**pip install flask-restful

3.基本使用:

定義Restful的類視圖:

從 flask_restful 中導(dǎo)入 Api ,來(lái)創(chuàng)建一個(gè) api 對(duì)象。 寫一個(gè)類視圖,讓他繼承自 Resource 類,然后在這個(gè)里面,使用 你想要的請(qǐng)求方式來(lái)定義相應(yīng)的方法,比如你想要將這個(gè)類視圖只 能采用 post 請(qǐng)求,那么就定義一個(gè) post 方法。 使用 api.add_resource 來(lái)添加類視圖與 url 。

from flask import Flask,url_for

pip install flask-restful

from flask_restful import Resource,Api app = Flask(name)

建立Api對(duì)象,并綁定應(yīng)用APP

api = Api(app) class LoginView(Resource): def get(self): return {“flag”:True} def post(self): return {“flag”:False}

建立路由映射

api.add_resource(LoginView,‘/login/’)

api.add_resource(LoginView,‘/login/’,‘/login2/’,endpoint=‘login’) with app.test_request_context():

werkzeug.routing.BuildError: Could not build url for endpoint ‘LoginView’.

Did you mean ‘loginview’ instead?

默認(rèn)沒有寫endpoint反向url_for函數(shù)通過小寫函數(shù)名

如果有多個(gè)url,會(huì)返回第1個(gè)URL

print(url_for(‘loginview’))

print(url_for(‘login’)) if name == ‘main’: app.run(debug=True)

注意

1 如果你想返回json數(shù)據(jù),那么就使用flask_restful,如果你是想渲染模版,那么還是采用之前 的方式,就是 app.route 的方式。

2 url還是跟之前的一樣,可以傳遞參數(shù)。也跟之前的不一樣,可以指定多個(gè)url。

3 endpoint是用來(lái)給url_for反轉(zhuǎn)url的時(shí)候指定的。如果不寫endpoint,那么將會(huì)使用視圖的 名字的小寫來(lái)作為endpoint。

4 add_resource的第二個(gè)參數(shù)是訪問這個(gè)視圖函數(shù)的url,這個(gè)url可以跟之前的route一樣,可 以傳遞參數(shù),并且還有一點(diǎn)不同的是,這個(gè)方法可以傳遞多個(gè)url來(lái)指定這個(gè)視圖函數(shù)。

Flask_RESTful參數(shù)驗(yàn)證

參數(shù)驗(yàn)證

參數(shù)驗(yàn)證也叫參數(shù)解析 Flask-Restful插件提供了類似WTForms來(lái)驗(yàn)證提交的數(shù)據(jù)是否合法 的包,叫做reqparse。

基本用法

1 通過 flask_restful.reqparse 中 RequestParser 建立解析器

2 通過 RequestParser 中的 add_argument 方法定義字段與解析規(guī)則

3 通過 RequestParser 中的 parse_args 來(lái)解析參數(shù)

1 解析正確,返回正確參數(shù)

2 解析錯(cuò)誤,返回錯(cuò)誤信息給前端

from flask import Flask from flask_restful import Api,Resource from flask_restful.reqparse import RequestParser app = Flask(name) api = Api(app) class RegisterView(Resource): def post(self):

建立解析器

parser = RequestParser()

定義數(shù)據(jù)的解析規(guī)則

parser.add_argument(‘uname’,type=str,required=True,help=‘用戶名驗(yàn)證錯(cuò)誤’,trim=True)

解析數(shù)據(jù)

args = parser.parse_args()

正確,直接獲取參數(shù)

print(args)

錯(cuò)誤,回饋到前端

響應(yīng)數(shù)據(jù)

return {‘msg’:‘注冊(cè)成功!!’}

建立映射關(guān)系

api.add_resource(RegisterView,‘/register/’) if name == ‘main’: app.run(debug=True)

add_argument方法參數(shù)詳解

add_argument方法可以指定這個(gè)字段的名字,這個(gè)字段的數(shù)據(jù)類 型等,驗(yàn)證錯(cuò)誤提示信息等,具體如下:

**1 default:**默認(rèn)值,如果這個(gè)參數(shù)沒有值,那么將使用這個(gè)參數(shù) 指定的默認(rèn)值。

2 required:是否必須。默認(rèn)為False,如果設(shè)置為True,那么這 個(gè)參數(shù)就必須提交上來(lái)。

**3 type:**這個(gè)參數(shù)的數(shù)據(jù)類型,如果指定,那么將使用指定的數(shù) 據(jù)類型來(lái)強(qiáng)制轉(zhuǎn)換提交上來(lái)的值??梢允褂胮ython自帶的一些 數(shù)據(jù)類型(如str或者int),也可以使用flask_restful.inputs下的一 些特定的數(shù)據(jù)類型來(lái)強(qiáng)制轉(zhuǎn)換。

url:會(huì)判斷這個(gè)參數(shù)的值是否是一個(gè)url,如果不是,那么就會(huì)拋出異常。

regex:正則表達(dá)式。

date:將這個(gè)字符串轉(zhuǎn)換為datetime.date數(shù)據(jù)類型。如果轉(zhuǎn)換不成功,則會(huì)拋出一個(gè)異常.

4 choices:固定選項(xiàng)。提交上來(lái)的值只有滿足這個(gè)選項(xiàng)中的值才 符合驗(yàn)證通過,否則驗(yàn)證不通過。

5 help:錯(cuò)誤信息。如果驗(yàn)證失敗后,將會(huì)使用這個(gè)參數(shù)指定的 值作為錯(cuò)誤信息。

**6 trim:**是否要去掉前后的空格

from flask import Flask from flask_restful import Api,Resource,inputs from flask_restful.reqparse import RequestParser app = Flask(name) api = Api(app) class RegisterView(Resource): def post(self):

建立解析器

parser = RequestParser()

定義解析規(guī)則

parser.add_argument(‘uname’,type=str,required=True,trim=True,help=‘用戶名不符合規(guī)范’)

網(wǎng)上學(xué)習(xí)資料一大堆,但如果學(xué)到的知識(shí)不成體系,遇到問題時(shí)只是淺嘗輒止,不再深入研究,那么很難做到真正的技術(shù)提升。

需要這份系統(tǒng)化的資料的朋友,可以戳這里獲取

一個(gè)人可以走的很快,但一群人才能走的更遠(yuǎn)!不論你是正從事IT行業(yè)的老鳥或是對(duì)IT行業(yè)感興趣的新人,都?xì)g迎加入我們的的圈子(技術(shù)交流、學(xué)習(xí)資源、職場(chǎng)吐槽、大廠內(nèi)推、面試輔導(dǎo)),讓我們一起學(xué)習(xí)成長(zhǎng)!

能采用 post 請(qǐng)求,那么就定義一個(gè) post 方法。

使用 api.add_resource 來(lái)添加類視圖與 url 。

from flask import Flask,url_for

pip install flask-restful

from flask_restful import Resource,Api app = Flask(name)

建立Api對(duì)象,并綁定應(yīng)用APP

api = Api(app) class LoginView(Resource): def get(self): return {“flag”:True} def post(self): return {“flag”:False}

建立路由映射

api.add_resource(LoginView,‘/login/’)

api.add_resource(LoginView,‘/login/’,‘/login2/’,endpoint=‘login’) with app.test_request_context():

werkzeug.routing.BuildError: Could not build url for endpoint ‘LoginView’.

Did you mean ‘loginview’ instead?

默認(rèn)沒有寫endpoint反向url_for函數(shù)通過小寫函數(shù)名

如果有多個(gè)url,會(huì)返回第1個(gè)URL

print(url_for(‘loginview’))

print(url_for(‘login’)) if name == ‘main’: app.run(debug=True)

注意

1 如果你想返回json數(shù)據(jù),那么就使用flask_restful,如果你是想渲染模版,那么還是采用之前 的方式,就是 app.route 的方式。

2 url還是跟之前的一樣,可以傳遞參數(shù)。也跟之前的不一樣,可以指定多個(gè)url。

3 endpoint是用來(lái)給url_for反轉(zhuǎn)url的時(shí)候指定的。如果不寫endpoint,那么將會(huì)使用視圖的 名字的小寫來(lái)作為endpoint。

4 add_resource的第二個(gè)參數(shù)是訪問這個(gè)視圖函數(shù)的url,這個(gè)url可以跟之前的route一樣,可 以傳遞參數(shù),并且還有一點(diǎn)不同的是,這個(gè)方法可以傳遞多個(gè)url來(lái)指定這個(gè)視圖函數(shù)。

Flask_RESTful參數(shù)驗(yàn)證

參數(shù)驗(yàn)證

參數(shù)驗(yàn)證也叫參數(shù)解析 Flask-Restful插件提供了類似WTForms來(lái)驗(yàn)證提交的數(shù)據(jù)是否合法 的包,叫做reqparse。

基本用法

1 通過 flask_restful.reqparse 中 RequestParser 建立解析器

2 通過 RequestParser 中的 add_argument 方法定義字段與解析規(guī)則

3 通過 RequestParser 中的 parse_args 來(lái)解析參數(shù)

1 解析正確,返回正確參數(shù)

2 解析錯(cuò)誤,返回錯(cuò)誤信息給前端

from flask import Flask from flask_restful import Api,Resource from flask_restful.reqparse import RequestParser app = Flask(name) api = Api(app) class RegisterView(Resource): def post(self):

建立解析器

parser = RequestParser()

定義數(shù)據(jù)的解析規(guī)則

parser.add_argument(‘uname’,type=str,required=True,help=‘用戶名驗(yàn)證錯(cuò)誤’,trim=True)

解析數(shù)據(jù)

args = parser.parse_args()

正確,直接獲取參數(shù)

print(args)

錯(cuò)誤,回饋到前端

響應(yīng)數(shù)據(jù)

return {‘msg’:‘注冊(cè)成功??!’}

建立映射關(guān)系

api.add_resource(RegisterView,‘/register/’) if name == ‘main’: app.run(debug=True)

add_argument方法參數(shù)詳解

add_argument方法可以指定這個(gè)字段的名字,這個(gè)字段的數(shù)據(jù)類 型等,驗(yàn)證錯(cuò)誤提示信息等,具體如下:

**1 default:**默認(rèn)值,如果這個(gè)參數(shù)沒有值,那么將使用這個(gè)參數(shù) 指定的默認(rèn)值。

2 required:是否必須。默認(rèn)為False,如果設(shè)置為True,那么這 個(gè)參數(shù)就必須提交上來(lái)。

**3 type:**這個(gè)參數(shù)的數(shù)據(jù)類型,如果指定,那么將使用指定的數(shù) 據(jù)類型來(lái)強(qiáng)制轉(zhuǎn)換提交上來(lái)的值??梢允褂胮ython自帶的一些 數(shù)據(jù)類型(如str或者int),也可以使用flask_restful.inputs下的一 些特定的數(shù)據(jù)類型來(lái)強(qiáng)制轉(zhuǎn)換。

url:會(huì)判斷這個(gè)參數(shù)的值是否是一個(gè)url,如果不是,那么就會(huì)拋出異常。

regex:正則表達(dá)式。

date:將這個(gè)字符串轉(zhuǎn)換為datetime.date數(shù)據(jù)類型。如果轉(zhuǎn)換不成功,則會(huì)拋出一個(gè)異常.

4 choices:固定選項(xiàng)。提交上來(lái)的值只有滿足這個(gè)選項(xiàng)中的值才 符合驗(yàn)證通過,否則驗(yàn)證不通過。

5 help:錯(cuò)誤信息。如果驗(yàn)證失敗后,將會(huì)使用這個(gè)參數(shù)指定的 值作為錯(cuò)誤信息。

**6 trim:**是否要去掉前后的空格

from flask import Flask from flask_restful import Api,Resource,inputs from flask_restful.reqparse import RequestParser app = Flask(name) api = Api(app) class RegisterView(Resource): def post(self):

建立解析器

parser = RequestParser()

定義解析規(guī)則

parser.add_argument(‘uname’,type=str,required=True,trim=True,help=‘用戶名不符合規(guī)范’)

[外鏈圖片轉(zhuǎn)存中…(img-poAkWhel-1715809606710)] [外鏈圖片轉(zhuǎn)存中…(img-GJ7GoECh-1715809606711)]

網(wǎng)上學(xué)習(xí)資料一大堆,但如果學(xué)到的知識(shí)不成體系,遇到問題時(shí)只是淺嘗輒止,不再深入研究,那么很難做到真正的技術(shù)提升。

需要這份系統(tǒng)化的資料的朋友,可以戳這里獲取

一個(gè)人可以走的很快,但一群人才能走的更遠(yuǎn)!不論你是正從事IT行業(yè)的老鳥或是對(duì)IT行業(yè)感興趣的新人,都?xì)g迎加入我們的的圈子(技術(shù)交流、學(xué)習(xí)資源、職場(chǎng)吐槽、大廠內(nèi)推、面試輔導(dǎo)),讓我們一起學(xué)習(xí)成長(zhǎng)!

柚子快報(bào)激活碼778899分享:鴻蒙 面試 學(xué)習(xí) 上傳文件

http://yzkb.51969.com/

參考鏈接

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19224402.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄