一、請(qǐng)求全局鉤子【hook】
此處的全局鉤子,其實(shí)就是類似django里面的中間件。 也就是只要調(diào)用或者注冊(cè)了,在http請(qǐng)求響應(yīng)中是必然執(zhí)行的。
在客戶端和服務(wù)器交互的過程中,有些準(zhǔn)備工作或掃尾工作需要處理,比如:
-
在項(xiàng)目運(yùn)行開始時(shí),建立數(shù)據(jù)庫連接,或創(chuàng)建連接池;
-
在客戶端請(qǐng)求開始時(shí),根據(jù)需求進(jìn)行身份識(shí)別,權(quán)限校驗(yàn);
-
在請(qǐng)求結(jié)束視圖返回?cái)?shù)據(jù)時(shí),指定轉(zhuǎn)換數(shù)據(jù)的格式,或者記錄操作日志;
請(qǐng)求鉤子是通過裝飾器的形式實(shí)現(xiàn),F(xiàn)lask支持如下四種請(qǐng)求鉤子(注意:鉤子的裝飾器名字是固定):
-
before_first_request
-
在處理第一個(gè)請(qǐng)求前執(zhí)行[項(xiàng)目剛運(yùn)行第一次被客戶端請(qǐng)求時(shí)執(zhí)行的鉤子]
-
-
before_request
-
在每一次請(qǐng)求前執(zhí)行[項(xiàng)目運(yùn)行后,每一次接收到客戶端的request請(qǐng)求都會(huì)執(zhí)行一次]
-
如果在某修飾的函數(shù)中返回了一個(gè)響應(yīng),視圖函數(shù)將不再被調(diào)用
-
-
after_request
-
如果沒有拋出錯(cuò)誤,在每次請(qǐng)求后執(zhí)行
-
接受一個(gè)參數(shù):視圖函數(shù)作出的響應(yīng)
-
在此函數(shù)中可以對(duì)響應(yīng)值在返回之前做最后一步修改處理
-
需要將參數(shù)中的響應(yīng)在此參數(shù)中進(jìn)行返回
-
-
teardown_request:
-
在每一次請(qǐng)求后執(zhí)行
-
接受一個(gè)參數(shù):錯(cuò)誤信息,如果有相關(guān)錯(cuò)誤拋出
-
需要設(shè)置flask的配置DEBUG=False,teardown_request才會(huì)接受到異常對(duì)象。
-
代碼
1 from flask import Flask, session 2 3 # 應(yīng)用實(shí)例對(duì)象 4 app = Flask(__name__) 5 6 """給app單獨(dú)設(shè)置配置項(xiàng)""" 7 # 設(shè)置秘鑰 8 app.config["SECRET_KEY"] = "my SECRET KEY" 9 10 @app.before_first_request 11 def before_first_request(): 12 """ 13 這個(gè)鉤子會(huì)在項(xiàng)目啟動(dòng)后第一次被用戶訪問時(shí)執(zhí)行 14 可以編寫一些初始化項(xiàng)目的代碼,例如,數(shù)據(jù)庫初始化,加載一些可以延后引入的全局配置 15 """ 16 print("----before_first_request----") 17 print("系統(tǒng)初始化的時(shí)候,執(zhí)行這個(gè)鉤子方法") 18 print("會(huì)在接收到第一個(gè)客戶端請(qǐng)求時(shí),執(zhí)行這里的代碼") 19 20 21 @app.before_request 22 def before_request(): 23 """ 24 這個(gè)鉤子會(huì)在每次客戶端訪問視圖的時(shí)候執(zhí)行 25 # 可以在請(qǐng)求之前進(jìn)行用戶的身份識(shí)別,以及對(duì)于本次訪問的用戶權(quán)限等進(jìn)行判斷。.. 26 """ 27 print("----before_request----") 28 print("每一次接收到客戶端請(qǐng)求時(shí),執(zhí)行這個(gè)鉤子方法") 29 print("一般可以用來判斷權(quán)限,或者轉(zhuǎn)換路由參數(shù)或者預(yù)處理客戶端請(qǐng)求的數(shù)據(jù)") 30 31 32 @app.after_request 33 def after_request(response): 34 print("----after_request----") 35 print("在處理請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法") 36 print("一般可以用于記錄會(huì)員/管理員的操作歷史,瀏覽歷史,清理收尾的工作") 37 38 response.headers["Content-Type"] = "application/json" 39 response.headers["Company"] = "python.Edu..." 40 41 # 必須返回response參數(shù) 42 return response 43 44 45 @app.teardown_request 46 def teardown_request(exc): 47 print("----teardown_request----") 48 print("在每一次請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法") 49 print("如果有異常錯(cuò)誤,則會(huì)傳遞錯(cuò)誤異常對(duì)象到當(dāng)前方法的參數(shù)中") 50 # 在項(xiàng)目關(guān)閉了DEBUG模式以后,則異常信息就會(huì)被傳遞到exc中,我們可以記錄異常信息到日志文件中 51 print(f"錯(cuò)誤提示:{exc}") # 異常提示 52 53 54 @app.route("/") 55 def index(): 56 print("-----------視圖函數(shù)執(zhí)行了---------------") 57 return "ok" 58 59 if __name__ == '__main__': 60 # 啟動(dòng)項(xiàng)目的web應(yīng)用程序 61 app.run(host="0.0.0.0", port=5000, debug=False)
在第1次請(qǐng)求時(shí)的打印(關(guān)閉DEBUG模式,視圖代碼正確執(zhí)行,沒有異常的情況):
----before_first_request---- 系統(tǒng)初始化的時(shí)候,執(zhí)行這個(gè)鉤子方法 會(huì)在接收到第一個(gè)客戶端請(qǐng)求時(shí),執(zhí)行這里的代碼 ----before_request---- 每一次接收到客戶端請(qǐng)求時(shí),執(zhí)行這個(gè)鉤子方法 一般可以用來判斷權(quán)限,或者轉(zhuǎn)換路由參數(shù)或者預(yù)處理客戶端請(qǐng)求的數(shù)據(jù) -----------視圖函數(shù)執(zhí)行了--------------- ----after_request---- 在處理請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 一般可以用于記錄會(huì)員/管理員的操作歷史,瀏覽歷史,清理收尾的工作 ----teardown_request---- 在每一次請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 如果有異常錯(cuò)誤,則會(huì)傳遞錯(cuò)誤異常對(duì)象到當(dāng)前方法的參數(shù)中 錯(cuò)誤提示:None
在第2次請(qǐng)求時(shí)的打印(關(guān)閉DEBUG模式,視圖代碼正確執(zhí)行,沒有異常的情況):
----before_request---- 每一次接收到客戶端請(qǐng)求時(shí),執(zhí)行這個(gè)鉤子方法 一般可以用來判斷權(quán)限,或者轉(zhuǎn)換路由參數(shù)或者預(yù)處理客戶端請(qǐng)求的數(shù)據(jù) -----------視圖函數(shù)執(zhí)行了--------------- ----after_request---- 在處理請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 一般可以用于記錄會(huì)員/管理員的操作歷史,瀏覽歷史,清理收尾的工作 ----teardown_request---- 在每一次請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 如果有異常錯(cuò)誤,則會(huì)傳遞錯(cuò)誤異常對(duì)象到當(dāng)前方法的參數(shù)中 錯(cuò)誤提示:None
在第1次請(qǐng)求時(shí)的打印(關(guān)閉DEBUG模式,視圖執(zhí)行錯(cuò)誤,有異常的情況):
----before_first_request---- 系統(tǒng)初始化的時(shí)候,執(zhí)行這個(gè)鉤子方法 會(huì)在接收到第一個(gè)客戶端請(qǐng)求時(shí),執(zhí)行這里的代碼 ----before_request---- 每一次接收到客戶端請(qǐng)求時(shí),執(zhí)行這個(gè)鉤子方法 一般可以用來判斷權(quán)限,或者轉(zhuǎn)換路由參數(shù)或者預(yù)處理客戶端請(qǐng)求的數(shù)據(jù) -----------視圖函數(shù)執(zhí)行了--------------- ----after_request---- 在處理請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 一般可以用于記錄會(huì)員/管理員的操作歷史,瀏覽歷史,清理收尾的工作 ----teardown_request---- 在每一次請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 如果有異常錯(cuò)誤,則會(huì)傳遞錯(cuò)誤異常對(duì)象到當(dāng)前方法的參數(shù)中 錯(cuò)誤提示:division by zero
在第2次請(qǐng)求時(shí)的打印(關(guān)閉DEBUG模式,視圖執(zhí)行有異常的情況):
----before_request---- 每一次接收到客戶端請(qǐng)求時(shí),執(zhí)行這個(gè)鉤子方法 一般可以用來判斷權(quán)限,或者轉(zhuǎn)換路由參數(shù)或者預(yù)處理客戶端請(qǐng)求的數(shù)據(jù) -----------視圖函數(shù)執(zhí)行了--------------- ----after_request---- 在處理請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 一般可以用于記錄會(huì)員/管理員的操作歷史,瀏覽歷史,清理收尾的工作 ----teardown_request---- 在每一次請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 如果有異常錯(cuò)誤,則會(huì)傳遞錯(cuò)誤異常對(duì)象到當(dāng)前方法的參數(shù)中 錯(cuò)誤提示:division by zero
鉤子裝飾器裝飾了多個(gè)函數(shù)的執(zhí)行順序如下:
from flask import Flask, session # 應(yīng)用實(shí)例對(duì)象 app = Flask(__name__) """給app單獨(dú)設(shè)置配置項(xiàng)""" # 設(shè)置秘鑰 app.config["SECRET_KEY"] = "my SECRET KEY" @app.before_first_request def before_first_request(): """ 這個(gè)鉤子會(huì)在項(xiàng)目啟動(dòng)后第一次被用戶訪問時(shí)執(zhí)行 可以編寫一些初始化項(xiàng)目的代碼,例如,數(shù)據(jù)庫初始化,加載一些可以延后引入的全局配置 """ print("----before_first_request----") print("系統(tǒng)初始化的時(shí)候,執(zhí)行這個(gè)鉤子方法") print("會(huì)在接收到第一個(gè)客戶端請(qǐng)求時(shí),執(zhí)行這里的代碼") @app.before_request def before_request(): """ 這個(gè)鉤子會(huì)在每次客戶端訪問視圖的時(shí)候執(zhí)行 # 可以在請(qǐng)求之前進(jìn)行用戶的身份識(shí)別,以及對(duì)于本次訪問的用戶權(quán)限等進(jìn)行判斷。.. """ print("----before_request----") print("每一次接收到客戶端請(qǐng)求時(shí),執(zhí)行這個(gè)鉤子方法") print("一般可以用來判斷權(quán)限,或者轉(zhuǎn)換路由參數(shù)或者預(yù)處理客戶端請(qǐng)求的數(shù)據(jù)") @app.after_request def after_request1(response): print("----after_request1----") print("在處理請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法") print("一般可以用于記錄會(huì)員/管理員的操作歷史,瀏覽歷史,清理收尾的工作") response.headers["Content-Type"] = "application/json" response.headers["Company"] = "python oldboy..." # 必須返回response參數(shù) return response @app.after_request def after_request2(response): print("----after_request2----") # 必須返回response參數(shù) return response @app.after_request def after_request3(response): print("----after_request3----") # 必須返回response參數(shù) return response @app.teardown_request def teardown_request(exc): print("----teardown_request----") print("在每一次請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法") print("如果有異常錯(cuò)誤,則會(huì)傳遞錯(cuò)誤異常對(duì)象到當(dāng)前方法的參數(shù)中") # 在項(xiàng)目關(guān)閉了DEBUG模式以后,則異常信息就會(huì)被傳遞到exc中,我們可以記錄異常信息到日志文件中 print(f"錯(cuò)誤提示:{exc}") # 異常提示 @app.route("/") def index(): print("-----------視圖函數(shù)執(zhí)行了---------------") return "ok" if __name__ == '__main__': # 啟動(dòng)項(xiàng)目的web應(yīng)用程序 app.run(host="0.0.0.0", port=5000, debug=False)
執(zhí)行效果:
----before_first_request---- 系統(tǒng)初始化的時(shí)候,執(zhí)行這個(gè)鉤子方法 會(huì)在接收到第一個(gè)客戶端請(qǐng)求時(shí),執(zhí)行這里的代碼 ----before_request---- 每一次接收到客戶端請(qǐng)求時(shí),執(zhí)行這個(gè)鉤子方法 一般可以用來判斷權(quán)限,或者轉(zhuǎn)換路由參數(shù)或者預(yù)處理客戶端請(qǐng)求的數(shù)據(jù) -----------視圖函數(shù)執(zhí)行了--------------- ----after_request3---- ----after_request2---- ----after_request1---- 在處理請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 一般可以用于記錄會(huì)員/管理員的操作歷史,瀏覽歷史,清理收尾的工作 ----teardown_request---- 在每一次請(qǐng)求以后,執(zhí)行這個(gè)鉤子方法 如果有異常錯(cuò)誤,則會(huì)傳遞錯(cuò)誤異常對(duì)象到當(dāng)前方法的參數(shù)中 錯(cuò)誤提示:None
結(jié)論:以視圖執(zhí)行為中心點(diǎn),before_request之前(請(qǐng)求過程)的先裝飾先執(zhí)行,after_request之后(響應(yīng)過程),后裝飾的先執(zhí)行。
二、
主動(dòng)拋出http異常
-
-
拋出一個(gè)給定狀態(tài)代碼的 HTTPException 或者 指定響應(yīng),例如想要用一個(gè)頁面未找到異常來終止請(qǐng)求,你可以調(diào)用 abort(404)
-
-
參數(shù):
-
from flask import Flask,abort,request app = Flask(import_name=__name__) # 配置類 class Config(object): DEBUG = True # 開啟調(diào)試模式 # 加載配置 app.config.from_object(Config) @app.route("/") def index(): # try: # 1/0 # except: # abort(500) username = request.args.get("username") if username is None: abort(400) return "ok" if __name__ == '__main__': app.run()
abort,只能拋出 HTTP 協(xié)議的錯(cuò)誤狀態(tài)碼,一般用于權(quán)限等頁面上錯(cuò)誤的展示提示.
捕獲錯(cuò)誤
-
-
注冊(cè)一個(gè)錯(cuò)誤處理程序,當(dāng)程序拋出指定錯(cuò)誤狀態(tài)碼的時(shí)候,就會(huì)調(diào)用該裝飾器所裝飾的方法
-
-
參數(shù):
-
code_or_exception – HTTP的錯(cuò)誤狀態(tài)碼或指定異常
-
-
@app.errorhandler(500) def internal_server_error(e): return '服務(wù)器搬家了'
捕獲指定異常類型
@app.errorhandler(ZeroDivisionError) def zero_division_error(e): return '除數(shù)不能為0'
代碼:
1 from flask import Flask, request, abort 2 3 # 應(yīng)用實(shí)例對(duì)象 4 app = Flask(__name__) 5 6 class APIError(Exception): 7 pass 8 9 """異常拋出""" 10 @app.route("/") 11 def index(): 12 username = request.args.get("username") 13 if username is None: 14 abort(400) 15 if username != "xiaoming": 16 raise APIError 17 return "ok" 18 19 20 @app.errorhandler(400) 21 def internal_server_error(e): 22 return { 23 "errno": 400, 24 "errmsg": "參數(shù)有誤!", 25 } 26 27 28 @app.errorhandler(APIError) 29 def api_error(e): 30 return { 31 "errno": 500, 32 "errmsg": "接口訪問有誤!", 33 } 34 35 36 if __name__ == '__main__': 37 # 啟動(dòng)項(xiàng)目的web應(yīng)用程序 38 app.run(host="0.0.0.0", port=5000, debug=True)
三、context
執(zhí)行上下文:即語境,語意,在程序中可以理解為在代碼執(zhí)行到某一行時(shí),根據(jù)之前代碼所做的操作以及下文即將要執(zhí)行的邏輯,可以決定在當(dāng)前時(shí)刻下可以使用到的變量,或者可以完成的事情。
Flask中提供的執(zhí)行上下文對(duì)象:相當(dāng)于一個(gè)容器,保存了 Flask 程序運(yùn)行過程中的一些信息[變量、函數(shù)、類與對(duì)象等信息]。
Flask中有兩種上下文,請(qǐng)求上下文(request context)和應(yīng)用上下文(application context)。
-
application 指的就是當(dāng)你調(diào)用
app = Flask(__name__)創(chuàng)建的這個(gè)對(duì)象app; -
request 指的是每次
http請(qǐng)求發(fā)生時(shí),WSGI server(比如gunicorn/uwsgi)調(diào)用Flask.__call__()之后,在Flask對(duì)象內(nèi)部創(chuàng)建的Request對(duì)象; -
application 表示用于響應(yīng)WSGI請(qǐng)求的應(yīng)用本身,request 表示服務(wù)端每次響應(yīng)客戶單的http請(qǐng)求;
-
application的生命周期大于request,一個(gè)application存活期間,可能發(fā)生多次http請(qǐng)求,所以也就會(huì)有多個(gè)
思考:在視圖函數(shù)中,如何取到當(dāng)前請(qǐng)求的相關(guān)數(shù)據(jù)?比如:請(qǐng)求地址,請(qǐng)求方式,cookie等等
在 flask 中,可以直接在視圖函數(shù)中使用 request 這個(gè)對(duì)象進(jìn)行獲取相關(guān)數(shù)據(jù),而 request 就是請(qǐng)求上下文提供的對(duì)象,保存了當(dāng)前本次請(qǐng)求的相關(guān)數(shù)據(jù),請(qǐng)求上下文提供的對(duì)象有:request、session
所以每次客戶端不同的請(qǐng)求,得到的request和session的對(duì)象都是同一個(gè),但是內(nèi)部的數(shù)據(jù)都是不一樣的。
-
request
-
封裝了HTTP請(qǐng)求的內(nèi)容,針對(duì)的是http請(qǐng)求。舉例:user = request.args.get('user'),獲取的是get請(qǐng)求的參數(shù)。
-
-
session
-
用來記錄請(qǐng)求會(huì)話中的信息,針對(duì)的是用戶信息。舉例:session['name'] = user.id,可以記錄用戶的狀態(tài)信息。還可以通過session.get('name')獲取用戶的狀態(tài)信息。
-
請(qǐng)求上下文提供的變量/屬性/方法/函數(shù)/類與對(duì)象,只能在視圖中或者被視圖調(diào)用的地方使用
代碼:
1 from flask import Flask, request, session 2 3 4 app = Flask(__name__) 5 6 app.config.update({ 7 "DEBUG": True, 8 "SECRET_KEY": "sklaasle3k2334" 9 }) 10 11 12 @app.route("/") 13 def index(): 14 print(request, id(request), request.args) 15 return "ok!" 16 17 18 if __name__ == '__main__': 19 # request寫在這里,就表示超出了用戶請(qǐng)求和響應(yīng)流程之外的地方了.會(huì)報(bào)錯(cuò). 20 # print(request) # RuntimeError: Working outside of request context. requset不能在情趣上傳文以外的地址被調(diào)用 21 # print(session) 22 app.run()
應(yīng)用上下文(application context)
它的字面意思是 應(yīng)用上下文,但它不是一直存在的,它只是request context 中操作當(dāng)前falsk應(yīng)用對(duì)象 app 的代理對(duì)象,就是所謂本地代理(local proxy)。它的作用主要是幫助 request 獲取當(dāng)前的flask應(yīng)用相關(guān)的信息,它是伴 request 而生,隨 request 而滅的。
應(yīng)用上下文提供的對(duì)象有:current_app,g
current_app
應(yīng)用程序上下文,用于存儲(chǔ)flask應(yīng)用實(shí)例對(duì)象中的變量,可以通過current_app.name打印當(dāng)前app的名稱,也可以在current_app中存儲(chǔ)一些變量,例如:
-
應(yīng)用的啟動(dòng)腳本是哪個(gè)文件,啟動(dòng)時(shí)指定了哪些參數(shù)
-
加載了哪些配置文件,導(dǎo)入了哪些配置
-
連接了哪個(gè)數(shù)據(jù)庫
-
有哪些可以調(diào)用的工具類、常量
-
當(dāng)前flask應(yīng)用在哪個(gè)機(jī)器上,哪個(gè)IP上運(yùn)行,內(nèi)存多大
代碼:
1 from flask import Flask,request,session,current_app,g 2 3 # 初始化 4 app = Flask(import_name=__name__) 5 6 # 聲明和加載配置 7 class Config(): 8 DEBUG = True 9 app.config.from_object(Config) 10 11 # 編寫路由視圖 12 @app.route(rule='/') 13 def index(): 14 # 應(yīng)用上下文提供給我們使用的變量,也是只能在視圖或者被視圖調(diào)用的地方進(jìn)行使用, 15 # 但是應(yīng)用上下文的所有數(shù)據(jù)來源于于app,每個(gè)視圖中的應(yīng)用上下文基本一樣 16 print(current_app.config) # 獲取當(dāng)前項(xiàng)目的所有配置信息 17 print(current_app.url_map) # 獲取當(dāng)前項(xiàng)目的所有路由信息 18 19 return "<h1>hello world!</h1>" 20 21 if __name__ == '__main__': 22 # 運(yùn)行flask 23 app.run(host="0.0.0.0")
g變量
g 作為 flask 程序全局的一個(gè)臨時(shí)變量,充當(dāng)者中間媒介的作用,我們可以通過它傳遞一些數(shù)據(jù),g 保存的是當(dāng)前請(qǐng)求的全局變量,不同的請(qǐng)求會(huì)有不同的全局變量,通過不同的thread id區(qū)別
g.name='abc' # name是舉例,實(shí)際要保存什么數(shù)據(jù)到g變量中,可以根據(jù)業(yè)務(wù)而定,你可以任意的數(shù)據(jù)進(jìn)去
代碼:
1 from flask import Flask,request,session,current_app,g 2 3 # 初始化 4 app = Flask(import_name=__name__) 5 6 # 聲明和加載配置 7 class Config(): 8 DEBUG = True 9 app.config.from_object(Config) 10 11 @app.before_request 12 def before_request(): 13 g.name = "root" 14 15 # 編寫路由視圖 16 @app.route(rule='/') 17 def index(): 18 # 請(qǐng)求上下文提供的變量/屬性/方法/函數(shù)/類與對(duì)象,只能在視圖中或者被視圖調(diào)用的地方使用 19 # 請(qǐng)求上下文里面信息來源于每次客戶端的請(qǐng)求,所以每個(gè)視圖中請(qǐng)求上下文的信息都不一樣 20 # print(session) 21 22 # 應(yīng)用上下文提供給我們使用的變量,也是只能在視圖或者被視圖調(diào)用的地方進(jìn)行使用, 23 # 但是應(yīng)用上下文的所有數(shù)據(jù)來源于于app,每個(gè)視圖中的應(yīng)用上下文基本一樣 24 print(current_app.config) # 獲取當(dāng)前項(xiàng)目的所有配置信息 25 print(current_app.url_map) # 獲取當(dāng)前項(xiàng)目的所有路由信息 26 index2() 27 index3() 28 return "ok!" 29 30 31 def index2(): 32 print(g.name) 33 34 def index3(): 35 print(g.name) 36 37 38 if __name__ == '__main__': 39 # 默認(rèn)情況下,應(yīng)用上下文提供的對(duì)象,也只能在客戶端的請(qǐng)求與響應(yīng)階段進(jìn)行調(diào)用。 40 # 但是工作中往往,需要在請(qǐng)求響應(yīng)之外,調(diào)用服務(wù)端信息,此時(shí),就必須要在請(qǐng)求響應(yīng)以外的地方調(diào)用current_app 41 # 例如:回頭使用celery實(shí)現(xiàn)異步任務(wù)或是定時(shí)任務(wù),那么如果任務(wù)里面需要操作數(shù)據(jù),則必須調(diào)用項(xiàng)目配置,那么就一定要使用current_app 42 with app2.app_context(): 43 print(current_app) 44 print(g) 45 app2.run()
兩者的區(qū)別:
-
-
應(yīng)用上下文:flask 應(yīng)用程序運(yùn)行過程中,保存的一些配置信息,比如路由列表,程序名、數(shù)據(jù)庫連接、應(yīng)用信息等
應(yīng)用上下文提供的對(duì)象,可以直接在請(qǐng)求上下文中使用,但是如果在請(qǐng)求上下文之外調(diào)用,則需要使用
with app.app_context()
四、終端腳本命令
在flask1.1版本之前版本中都是采用flask-script模塊來執(zhí)行終端腳本命令,flask1.1版本以后不再使用這個(gè)模塊了,因?yàn)榇嬖诩嫒菪詥栴}。
flask0.11.0版本以后,flask內(nèi)置了一個(gè)Click模塊,這個(gè)模塊是終端命令模塊,可以讓我們直接通過Click的裝飾器,編寫和運(yùn)行一些終端命令。在flask2.0版本已經(jīng)不能兼容flask-script模塊了,所以需要改成使用Click模塊來運(yùn)行和自定義管理終端命令了。
安裝了flask2.0以后,當(dāng)前項(xiàng)目所在的python環(huán)境就提供了一個(gè)全局的flask命令,這個(gè)flask命令是Click提供的。
# 要使用Click提供的終端命令flask,必須先在環(huán)境變量中聲明當(dāng)前flask項(xiàng)目的實(shí)例對(duì)象所在的程序啟動(dòng)文件。 # 例如:manage.py中使用了 app = Flask(__name__),則manage.py就是程序啟動(dòng)文件 # 使用flask終端命令之前,可以配置2個(gè)環(huán)境變量。 # 指定入口文件,開發(fā)中入口文件名一般:app.py/run.py/main.py/index.py/manage.py/start.py export FLASK_APP=manage.py # 指定項(xiàng)目所在環(huán)境 export FLASK_ENV=development # 開發(fā)環(huán)境,默認(rèn)開啟DEBUG模式 # export FLASK_ENV=production # 生成環(huán)境,默認(rèn)關(guān)閉DEBUG模式
默認(rèn)情況下,flask命令提供的子命令。
flask routes # 顯示當(dāng)前項(xiàng)目中所有路由信息 flask run # 把flask項(xiàng)目運(yùn)行在內(nèi)置的測(cè)試服務(wù)器下 # flask run --host=0.0.0.0 --port=5055 flask shell # 基于項(xiàng)目的應(yīng)用上下文提供終端交互界面,可以進(jìn)行代碼測(cè)試。
import click from flask import Flask, views app = Flask(__name__) # 配置 app.config.update({ "DEBUG": False, }) # 自定義終端命令 @app.cli.command("faker") # 假設(shè)這個(gè)用于生成測(cè)試數(shù)據(jù) @click.argument("data", default="user") # data表示生成數(shù)據(jù)的類型[參數(shù)argument是命令調(diào)用時(shí)的必填參數(shù)] @click.option('-n', 'number', type=int, default=1, help='生成的數(shù)據(jù)量.') # num表示測(cè)試數(shù)據(jù)的生成數(shù)量[選項(xiàng)option是命令調(diào)用時(shí)的可選參數(shù)] def faker_command(data, number): """添加測(cè)試信息""" print("添加測(cè)試信息") print(f"數(shù)據(jù)類型:data={data}") print(f"生成數(shù)量:number={number}") @app.route("/") def index(): return "ok" if __name__ == '__main__': app.run() """ flask faker --help flask faker -n10 user flask faker user """
終端下的運(yùn)行效果:
(flask) moluo@ubuntu:~/Desktop/flaskdemo$ flask faker -n10 user 添加測(cè)試信息 數(shù)據(jù)類型:data=user 生成數(shù)量:number=10 (flask) moluo@ubuntu:~/Desktop/flaskdemo$ flask faker user 添加測(cè)試信息 數(shù)據(jù)類型:data=user 生成數(shù)量:number=1 (flask) moluo@ubuntu:~/Desktop/flaskdemo$ flask faker goods 添加測(cè)試信息 數(shù)據(jù)類型:data=goods 生成數(shù)量:number=1
練習(xí):
1. flask2.0的終端下,輸入 python manage.py startapp home 則可以在當(dāng)前目錄下創(chuàng)建以下目錄和文件
項(xiàng)目目錄/
└── home
├── views.py
├── models.py
├── urls.py
└── tests.py
代碼:
import click, os from flask import Flask app = Flask(__name__) # 配置 app.config.update({ "DEBUG": False }) @app.cli.command("startapp") @click.argument("name") # @click.option('-n', 'name', help='app name') def startapp(name): """生成子模塊或子應(yīng)用""" if os.path.isdir(name): print(f"當(dāng)前{name}目錄已存在!請(qǐng)先處理完成以后再創(chuàng)建。") return os.mkdir(name) open(f"{name}/views.py", "w") open(f"{name}/models.py", "w") open(f"{name}/documents.py", "w") open(f"{name}/ws.py", "w") open(f"{name}/services.py", "w") open(f"{name}/urls.py", "w") open(f"{name}/test.py", "w") print(f"{name}子應(yīng)用創(chuàng)建完成....") @app.route("/") def index(): return "ok" if __name__ == '__main__': app.run()
終端調(diào)用:
flask startapp home flask startapp users
六、jinja2模板引擎
Flask內(nèi)置的模板語言Jinja2,它的設(shè)計(jì)思想來源于 Django 的模板引擎DTP(DjangoTemplates),并擴(kuò)展了其語法和一系列強(qiáng)大的功能。
-
Flask提供的 render_template 函數(shù)封裝了該模板引擎Jinja2
-
render_template
app = Flask(__name__,template_folder='templates')
2、
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ title }}</title> </head> <body> <h1>{{ content }}</h1> </body> </html>
3、在視圖函數(shù)設(shè)置渲染模板并設(shè)置模板數(shù)據(jù)
from flask import Flask, render_template # 默認(rèn)情況下,flask默認(rèn)直接支持視圖加載模板的。 # Flask類在實(shí)例化的時(shí)候,默認(rèn)當(dāng)前根目錄下的templates目錄作為模板目錄 app = Flask(__name__, template_folder="templates") # 配置 app.config.update({ "DEBUG": True }) @app.route("/") def index(): data = { "title": "我的模板標(biāo)題", "content": "我的模板內(nèi)容" } return render_template("index.html", **data) @app.route("/user/<id>") def user(id): title = "User Center" content = "我的個(gè)人中心" print(locals()) # {'id': '100', 'title': 'User Center', 'content': '我的個(gè)人中心'} return render_template("user.html", **locals()) if __name__ == '__main__': app.run()
浙公網(wǎng)安備 33010602011771號(hào)