第二篇 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__)  # 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM