Flask上下文管理

1、一些python的知識

一、偏函數

複製代碼
def add(x, y, z):
    print(x + y + z)


# 本來的寫法:x,y,z能夠傳任意數字
add(1,2,3)


# 若是我要實現一個功能,這三個數中,其中一個數必須是3
# 咱們就可使用偏函數來幫着咱們傳參
from functools import partial

# partial:給add這個函數固定傳一個數字 3
new_add = partial(add, 3)

# 所以新的函數只須要傳2個參數
new_add(1,1)
new_add(1,2)


# 偏函數:就是幫咱們給一個函數固定一個參數
# new_add(x1, x2) --> add(3, x1, x2)
複製代碼

 

二、類的兩個雙下方法

複製代碼
1. __getattr__:對象獲取屬性值的時候觸發

2. __setattr__:對象設置屬性值的時候觸發

3.示例
class A(object):
    def __init__(self):
        # self.name = {}
        # 初始化的時候,給這個對象設置一個屬性名爲name,值爲空的字典
        object.__setattr__(self, "name", {})

    def __getattr__(self, item):
        print("getattr: ", item)

    def __setattr__(self, key, value):
        print("setattr: ", self.name)
        print("setattr: ", key, value)
        self.name[key] = value
        print("setattr: ", self.name)


# 實例化,調用__init__
a = A()

# 獲取對象某個屬性的值,會調用__getattr__
# 若是A這個類沒有__getattr__,就會去執行父類的__getattr__
# 可是嚴謹的__getattr__是:若是你沒有這個屬性,就會給你報錯
# 咱們能夠在A類重寫__getattr__,可讓它不報錯
a.xxx  # getattr:  xxx

# 給對象的某個屬性設置值,會調用__setattr__
# 執行的邏輯跟__getattr__同樣,A類沒有就去調用父類的
a.xxx = '小明'
# 首先打印name字典的默認值:是個空字典 setattr:  {}
# setattr的key是左邊的變量,value是右邊的值:setattr:  xxx 小明
# 打印self.name這個字典:setattr:  {'xxx': '小明'}
複製代碼

 

2、Flask上下文管理

Flask的上下文管理咱們能夠理解爲一個生命週期
也就是請求進來到請求出去一共作了哪些事情
首先咱們知道項目啓動執行了app.run()方法,調用了werkzeug的run_simple()方法
run_simple(host, port, self, **options) 這時候的self就是咱們的app
run_simple會執行self(),也就是app(), 那麼app = Flask() 因此會走Flask的__call__方法前端

那麼__call__作了什麼呢

environ是咱們請求來的原始數據~當成參數傳遞給了request_context方法python

 


進入這個RequestContext對象flask

 


這是初始化這個類作的一些事情
在這裏從新封裝了request, 以及給session 賦值了 None
也就是說:
ctx = RequestContext(app, environ)
ctx.request 是從新封裝的request
ctx.session = Nonecookie

 

繼續
session


執行了_request_ctx_stack.push(ctx)
也就是說_request_ctx_stack它把咱們的ctx對象push到了一個地方
咱們的ctx這個對象裏面有request以及session等數據結構

 


這個初始化方法就是剛纔python類的雙下方法__setattr__
就是給Local類初始化了兩個屬性    __storage__ = {}            __ident_func__ = get_identapp

 

咱們繼續看LocalStark中push方法作了什麼
ide


如今回去看wsgi_app裏的ctx.push(),到這裏,它就走完了,接下來就要走視圖
那到這裏咱們能夠經過什麼樣的方法在咱們視圖中拿到這個request對象呢
request在ctx對象裏能經過ctx.request獲得,那咱們怎麼獲得ctx呢
ctx被LocalStack對象放入到Local中了函數

from flask import Flask
from flask import globals

app = Flask(__name__)


@app.route("/")
def index():
    ctx = globals._request_ctx_stack.top
    print(ctx.request.method)
    return "index"



if __name__ == '__main__':
    app.run()
獲取ctx

 

3、Flask上下文管理(續)

這個request:
  from flask.globals import _request_ctx_stack
  ctx = _request_ctx_stack.top
  request = ctx.requestpost


和這個request:
  from flask import request


兩個request有什麼區別?


其實咱們導入的request跟咱們上面拿到的request是同樣的。

下面看看怎麼直接拿request

reqeust是LocalProxy這個類的實例化對象,參數是一個偏函數,
那當咱們調用request.method 等方法的時候走的是LocalProxy這個類的__getattr__方法

這裏的_get_current_object()至關於咱們偏函數的執行

 

所以,直接導入的request也是經過LocalStack方法去Local中取ctx對象
而後經過getattr 找到ctx.request,
也就是說這個LocalProxy就是一個幫助咱們取值的代理,讓咱們的取值變的更加簡單
這個代理經過偏函數來綁定參數,
ctx中封裝了request,以及session,只不過到這裏咱們的session依然是空的。

 

4、session的實現原理

 _request_ctx_stack.push(self)走完後,會繼續走這個

也就是說,請求進來把ctx放入Local中後,從前端解密了cookie,而後把解密數據好的數據給了self.session
繼續走

那麼session的實現機制:
  1. 請求進來獲取cookie的值
  2. 解密cookie轉換成字典(沒有cookie就是空字典)賦值給ctx.session
  3. 當請求走的時候把session的數據加密
  4. 設置cookie

 

5、應用上下文管理

 應用上下文和請求上下文的原理和源碼是同樣的

也就是說,咱們請求上下文和應用上下文,分別創建了兩個Local對象
兩個Local對象數據結構都是同樣的,那麼請求上下文和應用上下文爲何要分開存放呢
由於咱們寫離線腳本的時候須要用到!

 

小結:
也就是說能夠導入請求上下文的request, session和應用上下文的g, current_app
from flask import Flask, request, session, g, current_app

 

6、全局對象g

咱們說應用上下文裏封裝了g對象,那麼這個g對象是什麼呢
1. Flask中g的生命週期?
  咱們講這麼多上下文管理,咱們知道請求進來會爲每一個請求在Local中創建一個獨立空間
  也就是在應用上下文的Local對象中創建了一個g對象,當請求走的時候就會刪除
  因此g的生命週期是一次請求的進來到離開。

 

2. g和session有什麼區別?
  session有cookie,下次請求進來的時候能帶數據過來

 

3. g和全局對象有什麼區別?
  全局變量,是在項目啓動建立的,直到項目中止纔會銷燬
  不管多少請求進來均可以訪問全局變量
  而咱們的g對象通常狀況用於before_request中設置值,只爲這一次請求創建全局變量

 

4. Demo

複製代碼
from flask import Flask, request, session, g, current_app
from flask.globals import _request_ctx_stack


app = Flask(__name__)


@app.before_request
def auth():
    g.xxx = "小明"


@app.route("/")
def index():
    ctx = _request_ctx_stack.top
    print(ctx.request)
    print(ctx.request.method)
    print(current_app)
    # request.xxx的執行過程
    # 1. request --> LocalProxy(偏函數)
    # 2. request.xxx --> LocalProxy  __getattr__
    # 3. __getattr__  --> getattr(偏函數的執行,xxx )
    # 4. 偏函數-->  _request_ctx_stack.top.request

    print(g.xxx)
    return "INDEX"


if __name__ == '__main__':
    app.run()
複製代碼

 

7、Flask上下文管理圖解

相關文章
相關標籤/搜索