1. 程式人生 > >第二篇 Flask基礎篇之(閃現,藍圖,請求擴展,中間件)

第二篇 Flask基礎篇之(閃現,藍圖,請求擴展,中間件)

UNC sage 詳情 mes 做的 spa 方法 裝飾器。 edi

本篇主要內容:

  閃現

  請求擴展  

  中間件  

  藍圖

寫裝飾器,常用 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__)  # f1
View 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基礎篇之(閃現,藍圖,請求擴展,中間件)