第二篇 Flask基礎篇之(閃現,藍圖,請求擴展,中間件)
本篇主要內容:
閃現
請求擴展
中間件
藍圖
寫裝飾器,常用 functools模塊,幫助設置函數的元信息
import functools def wrapper(func): @functools.wraps(func) def inner(*args,**kwargs): return func(*args,**kwargs) return inner @wrapper def f1(): pass print(f1.__name__) # f1View Code
續接第一篇
8.Flask之閃現
#首先要導入flash 和 get_flashed_messages from flask import Flask,flash,get_flashed_messages app = Flask(__name__) app.secret_key="1234" @app.route("/get") def get(): # 2.從某個地方獲取設置過的所有值,並清除。 類似於pop # 第一次運行可以獲取到所有的設置的值;第二次運行就清除掉了所有的設置的值 data = get_flashed_messages() print(data) return "hello World" @app.route("/set") def set(): # 1. 向某個地方設置一個值 flash("軍人") return "Hello army" if __name__=="__main__": app.run()
閃現有什麽作用呢?
比如:假設在A頁面做個操作,但該操作失敗了,要跳轉到B頁面並顯示這些錯誤信息
from flask import Flask,flash,get_flashed_messages,request,redirect app = Flask(__name__) app.debug = True app.secret_key="1234" @app.route("/index") def index(): # get請求用request.args.get, v是接受參數的變量 # 瀏覽器請求: val = request.args.get(‘v‘) if val =="body": return "hello World, guys" # 如果請求參數不是body,則跳轉到錯誤頁面,需要將錯誤信息flash,也就是設置錯誤值到某個地方 # A.flash不分類,直接設置值 flash("前端輸入參數錯誤") # B.flash還可以對錯誤信息,進行分類 flash("前端輸入參數錯誤", category="x1") return redirect("/error") @app.route("/error") def error(): ‘‘‘ 顯示錯誤信息 ‘‘‘ # 跳轉到error頁面後,請求時獲取錯誤信息 # A.flash沒有分類時 # data = get_flashed_messages() # 獲取的就是flash的值 # B. 對於有分類的,取值時可以通過 category_filter 根據分類取錯誤信息 data = get_flashed_messages(category_filter=[‘x1‘]) # 可能有很多的錯誤信息,也可以按照索引的方式取出錯誤值 if data: msg = data[0] else: msg = "..." return "錯誤信息:%s" %(msg) if __name__=="__main__": app.run()
閃現是怎麽實現的呢?
其實,它就是通過session做的,先把數據存在session裏,數據如果在session裏,只要不刪,就永遠在。
然後,如果值被拿走,就會通過session.pop()的方式給拿走。
所以,就不用擔心數據錯亂。因為每個用戶都會有自己的一個session,基於session就會把數據隔離開了。
閃現的應用:
對臨時數據操作,如:顯示錯誤信息
9.Flask之請求擴展(類似Django中間件)--其實也是Flask的中間件
場景:
商業應用一般都要求登錄後才可以進行其他操作,上一篇我們基於裝飾器的方式做,但是如果函數越來越多,那就要新增一個函數,就要添加一個裝飾器。
為了省事,在Django裏通過中間件的方式做的,但是Flask裏沒有類似的中間件,就需要通過Flask裏的請求擴展的方式做。
(1)做用戶登錄認證 before_request —常用
示例:基於Flask的請求擴展做一個用戶認證功能
from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) app.debug = True app.secret_key = "123#234" USERS = { 1:{"name":"老大", "age":19,"gender":"男", "resume":"言語措辭間都能體會到今日頭條的謹小慎微,生怕再出現任何問題……."}, 2:{"name":"老二", "age":18,"gender":"女", "resume":"當打開這款APP之後,就會發現這跟已經“死”去的內涵段子簡直是一模一樣。更厲害的地方是,它還支持用用戶遷移內涵段子上的內容信息。"}, 3:{"name":"老三", "age":17,"gender":"男", "resume":"如果狒狒會說人話,他肯定是在說:餵…你怎麽只給我吃了一口就跑了呀,我還沒吃飽啊…餵餵餵…給我回來呀!哈哈哈"}, } # 基於flask裏請求擴展來做 @app.before_request def process_request(*args, **kwargs): # 驗證表示,任何地址請求都會先執行before_request,所以登錄驗證就可以在before_request裏做用戶認證功能了 print("其他請求之前就執行了process_request") # 4.訪問/login的時候還沒有登錄,就會一直重定向到登錄頁,所以就要設置個白名單,如果請求地址是/login,就返回None if request.path == "/login": return None # 1.登錄驗證功能 user = session.get(‘user_info‘) # 2.如果登錄信息正常,什麽都不做,程序繼續其他執行 if user: return None # 3.如果登錄驗證不通過,就重定向到登錄頁面 return redirect("/login") @app.route("/detail/<int:nid>", methods=[‘GET‘]) def detail(nid): detail_info = USERS.get(nid) # 如果有值,就跳到詳情頁 return render_template("detail.html",info = detail_info) @app.route("/index", methods=[‘GET‘]) def index(): return render_template("index.html", user_dict=USERS) @app.route("/login", methods=[‘GET‘, ‘POST‘], endpoint=‘l1‘) def login(): if request.method =="GET": return render_template("login.html") else: user = request.form.get("username") pwd = request.form.get("password") if user == "alex" and pwd =="123456": session[‘user_info‘] = user return redirect("/index") return render_template("login.html", **{"error":"用戶名和密碼錯誤"}) if __name__ == "__main__": app.run()
(2)有before_request, 就天然的有after_request —常用
from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) app.debug = True app.secret_key = ‘siuljskdjfs‘ @app.before_request def process_request1(*args,**kwargs): print(‘process_request1 進來了‘) @app.after_request def process_response1(response): print(‘process_response1 走了‘) # after_request 必須返回 response return response # 視圖函數 @app.route(‘/index‘,methods=[‘GET‘]) def index(): print(‘index函數‘) return "Index" if __name__ == ‘__main__‘: app.run()
(3)請求擴展可以添加多個
from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) app.debug = True app.secret_key = ‘siuljskdjfs‘ @app.before_request def process_request1(*args,**kwargs): print(‘process_request1 進來了‘) return "攔截" @app.before_request def process_request2(*args,**kwargs): print(‘process_request2 進來了‘) @app.after_request def process_response1(response): print(‘process_response1 走了‘) # after_request 必須返回 response return response @app.after_request def process_response2(response): print(‘process_response2 走了‘) return response # 視圖函數 @app.route(‘/index‘,methods=[‘GET‘]) def index(): print(‘index函數‘) return "Index" if __name__ == ‘__main__‘: app.run() ‘‘‘ Flask請求擴展也可以寫多個 但是要註意,多個請求擴展的執行順序是有差別的: 對於before_request,是按照寫的代碼的順序從上到下的順序正序執行的 對於after_request, 是按照寫的代碼的順序從下到上的順序倒序執行的 如果before_request return了(即程序被攔截了),其他before_request就不執行了,但是所有的after_request都會繼續執行 ‘‘‘
(4)定制錯誤信息:errorhandler(404)
from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) app.debug = True app.secret_key = ‘siuljskdjfs‘ # 經常會出現url不存在的情況,一般會有錯誤信息 # 而這個錯誤信息也是可以進行定制的,根據錯誤碼定制錯誤信息方法如下: @app.errorhandler(404) def error_404(arg): return "404錯誤了" # 視圖函數 @app.route(‘/index‘,methods=[‘GET‘]) def index(): print(‘index函數‘) return "Index" if __name__ == ‘__main__‘: app.run()
(5)模板中定制方法(定制模板方法): template_global() 和 template_filter()
from flask import Flask,request app = Flask(__name__) app.debug = True # 這就是基於請求擴展的 定制模板方法
# 相對於在模板裏定制了一個函數
@app.template_global() def sb(a1, a2): return a1 + a2 if __name__ == ‘__main__‘: app.run() #在HTML裏調用的方式如下: {{sb(1,2)}}
from flask import Flask,request app = Flask(__name__) app.debug = True # 這就是基於請求擴展的 定制模板方法 @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3 if __name__ == ‘__main__‘: app.run() #在HTML裏調用的方式如下: {{ 1|db(2,3)} # 參數 a1 = 1,是第一個參數; a2=2 是第二個參數; a3=3 是第三個參數
(6)只有第一次請求才執行的:before_first_request
比如:數據庫的連接,初始化操作
from flask import Flask,request app = Flask(__name__) app.debug = True # 內部其實就有個判斷,初始值是FALSE,第一次執行後將值改變為True,以後判斷後就不執行了 @app.before_first_request def before_first_request2(): print(‘before_first_request2‘) if __name__ == ‘__main__‘: app.run()
10. 中間件
前面關於請求的中間件已經在請求擴展裏講了。
由於知道請求之前會執行一個wsgi_app,所以這裏做個請求之前的定制,先了解一下
from flask import Flask app = Flask(__name__) @app.route("/login", methods=[‘GET‘, ‘POST‘]) def index(): pass class Md(object): def __init__(self, old_wsgi_app): self.old_wsgi_app = old_wsgi_app def __call__(self, environ, start_response): print("開始之前") ret = self.old_wsgi_app(environ, start_response) print("結束之後") return ret if __name__ =="__main__": app.wsgi_app = Md(app.wsgi_app) # 相當於把wsgi_app給更新了 app.run()
11.藍圖
前置情景:一個項目一般會有多個.py文件組成,這些.py文件分別執行不同的功能,那就可以為這些不同功能的.py文件給劃分到不同的目錄裏去。
所以藍圖用於為應用提供目錄劃分:
未使用藍圖的目錄結構,但是沒有Flask提供的藍圖好,藍圖裏還提供了一些類似請求擴展的東西等等。
使用藍圖的目錄結構
使用藍圖的目標:
1. 構造程序目錄
2. 自定義程序目錄
批量處理url
定制模板路徑和靜態文件路徑
請求擴展:
- 可以針對app, 即全部程序都生效
- 也可以針對單個的藍圖,即只有在執行該藍圖時,請求擴展才會生效
從Flask的官方文檔可知,藍圖需要掌握的幾個方面知識點如下:
1. 註冊藍圖
2. 藍圖資源
3. 靜態文件
4. 模板
5. 構造URL
第二篇 Flask基礎篇之(閃現,藍圖,請求擴展,中間件)