1. 程式人生 > >Flask基礎(3):session、flash、特殊裝飾器、藍圖、路由正則匹配、上下文管理 & flask-session

Flask基礎(3):session、flash、特殊裝飾器、藍圖、路由正則匹配、上下文管理 & flask-session

Session:

Flask 預設將 session 以加密的形式放到了瀏覽器的 cookie 中 
Flask 的 session 就是一個字典,字典有什麼方法 session 就有什麼方法
flask session 原理:當請求剛進來時,flask會讀取cookie中 session(配置檔案中能改這個名稱) 對應的值,將這個值解密並反序列化成為一個字典放入記憶體,
                    以便檢視函式使用;
                    在檢視函式中使用時,按照字典的方法使用;
                    當請求結束時,flask會讀取記憶體中字典的值,進行序列化
+加密,然後再寫入到使用者的 cookie 中

flash:

# flash 是 取一次就沒有;基於 session 實現的
# 原理:在 session 中儲存一個數據,讀取時通過 pop 將資料移除,從而達到只能取一次的效果
from flash import get_flashed_messages
flash("臨時資料儲存","error")  # 存 flash;"error" 表示分類
get_flashed_messages()   # 取 flash 中的值;列表的形式; get_flashed_messages(category_filter=["error"]) 表示根據 分類取 flash

特殊裝飾器:(重點)

  **1. @app.before_request  # 所有請求之前進行的操作;被裝飾的函式沒有 引數 和 返回值;作用類似於 Django 的 process_request
    2. @app.template_global()  # 給模板用的
    3. @app.template_filter()  # 給模板用的
    
  **4. @app.after_request  # 被裝飾的函式要有 引數 和 返回值;作用類似於 Django 的 process_response
        
        @app.after_request
        
def test(response): print("after_request") return response # 對於有多個 @app.before_request ,誰先定義誰先執行;對於有多個 @app.after_request ,誰先定義誰後執行;類似於 Django 中介軟體的執行順序 # 對於 before_request,可以在定義自己邏輯時新增返回值,這樣就不會執行後面的 before_request 和 檢視,但還會執行所有的 after_request;這是和 Django(1.10以後版本不一樣的地方) 5. @app.before_first_request # 只有第一次請求才執行 6. @app.errorhandler(錯誤碼) # 報錯的時候執行的函式;可用於定製錯誤資訊(頁面) @app.errorhandler(404) def not_found(arg): # arg 是錯誤資訊 print(arg) return "沒找到"

Blueprint:藍圖

示例目錄:

crm
|---crm
    |--- __init__.py  # 例項化 Flask 等等
    |---views
        |---account.py
        |---user.py
|---manage.py  # 入口函式

manage.py

from crm import create_app

app = create_app()  

if __name__ == '__main__':
    app.run()  # 執行 Flask 的例項

crm/__init__.py

from flask import Flask
from .views.account import ac
from .views.user import uc

def create_app():

    app = Flask(__name__)

    # @app.before_request   # 全域性性的 before_request
    # def x1():
    #     print('app.before_request')

    app.register_blueprint(ac)
    app.register_blueprint(uc,url_prefix='/api')  # 給 uc 這個藍圖的 url 新增一個 字首
    return app

crm/views/account.py

from flask import Blueprint,render_template

ac = Blueprint('ac',__name__)  # 例項化一個藍圖

@ac.before_request  # 只給 ac 這個藍圖新增 before_request
def x1():
    print('app.before_request')

@ac.route('/login')
def login():
    return render_template('login.html')


@ac.route('/logout')
def logout():
    return 'Logout'

crm/views/user.py

from flask import Blueprint

uc = Blueprint('uc',__name__)

@uc.route('/list')
def list():
    return 'List'

@uc.route('/detail')
def detail():
    return 'detail'

藍圖的作用:

1. 目錄結構的劃分
2. 路徑加字首
3. 給某些應用(檢視)加裝飾器

路由的正則匹配:

# 1. 先定義一個類: RegexConverter(BaseConverter)
# 2. app.url_map.converters["reg"] = RegexConverter
# 3. 使用者傳送請求
# 4. 使用自定義正則:
    @app.route("/index/<reg('\d+'):nid>")
    def index(nid):
        print(nid,type(nid)
        print(url_for('index',nid=987)  # 返回生成url時,自動觸發 RegexConverter 的 to_url 方法
# 4. flask內部進行正則匹配
# 5. to_python 方法的返回值會交給檢視函式的引數

上下文管理:

1. request
2. session  # 注: Flask 預設將 session 以加密的形式放到了瀏覽器的 cookie 裡面
3. app
4. g

請求--檢視--響應 大致流程:

請求到來時:
    # ctx = RequestContext(self,environ)  # self 是 app物件,environ表示請求相關的原始資料
    # ctx.request = Request(environ)  
    # ctx.session = None
    
    # 將包含了 request和session 的ctx物件打包放到某個地方(相當於一個大字典;根據執行緒或協程加個唯一標識,放進去的,所以資料相互隔離)
        {
            1232:{ctx:ctx物件},
            ...
        }
檢視函式:
    from flask import request,session
    # 上述程式碼背後的過程:根據當前執行緒或者協程的唯一標識,取到 ctx物件,然後取到 request和session
請求結束:
    根據當前執行緒的唯一標識,將 大字典 中該執行緒對應的資料移除

上下文管理--request:

# 1. wsgi:初步處理請求
# 2. __call__ 方法 --> wsgi_app 方法
# 3. wsgi_app方法:
        ctx = RequestContext(session,request)
        ctx.push()
# 4. LocalStack:把 ctx 物件新增到 Local 中 (LocalStack起到一箇中介的作用;檢視函式取值時也是來 LocalStack 中取值,而不能直接去 Local 中取)
# 5. Local:為每個執行緒或協程開闢一塊相互隔離的記憶體空間; local物件中有一個 __storage__ 的字典
        __storage__ = {
            執行緒/協程唯一標識:{"stack":[ctx物件(request和session),]}
        }

上下文管理--session:

# 通過 LocalStack 獲取 ctx 中的 session,給 session 賦值(從 cookie 中讀取資料,進行解密和反序列化;呼叫 open_session() 方法)

補充:

# Flask 和 Django 對比:
    相同點:都是基於 wsgi 協議寫的
    最大不同點:request的機制不同:請求相關的資料,對於Django是通過引數傳遞一個一個傳遞過來的;flask是把請求相關的資料放到“一個地方”(大字典),以後就來這裡取對應的資料

# 全域性變數只有在初次載入時執行
# 類中的 __slots__() 的作用:在類外面只有 ()中的屬效能通過 . 獲取到,如: __slots__("name") ,只能獲取到 obj.name

flask-session:

# Flask 第三方元件--flask-session:可將 session 儲存到 redis 中

安裝:

pip install flask-session  

使用:

import redis
from flask import Flask,request
from flask_session import Session  # 匯入 flask-session 中的 Session

app = Flask(__name__)

app.config["SESSION_TYPE"] = "redis"  # 3. 由下面的分析可知,配置檔案中應該要先配置好 SESSION_TYPE; 此時 app.session_interface = RedisSessionInterface();RedisSessionInterface 中也有 open_session 和 save_session 這兩個方法
app.config["SESSION_REDIS"] = redis.Redis(host="127.0.0.1",port=6379,password="")  # 4. 配置 session 的 Redis
# 通過這些操作, session 就會儲存到 redis 中;此時儲存在 瀏覽器中的 cookie 是一個 隨機字串(uuid.uuid4()),當請求到達時 通過這個 cookie(隨機字串)來 redis 中取 session

# 1. flask 預設的 session 處理是通過 app.session_interface = SecureCookieSessionInterface()
Session(app)
# 2. app 經過 Session 例項化之後,app.session_interface = self._get_interface(app) ; session 儲存到哪和 配置檔案中的 "SESSION_TYPE" 有關

pass