Flask中current_app和g對象

Flask中有兩種上下文,請求上下文和應用上下文。

請求上下文(request context)

request和session都屬於請求上下文對象。

request:封裝了HTTP請求的內容,針對的是http請求。舉例:user = request.args.get('user'),獲取的是get請求的參數。

session:用來記錄請求會話中的信息,針對的是用戶信息。舉例:session['name'] = user.id,可以記錄用戶信息。還可以通過session.get('name')獲取用戶信息。

應用上下文(application context)

current_app和g都屬於應用上下文對象。

current_app:表示當前運行程序文件的程序實例。

g:處理請求時,用於臨時存儲的對象,每次請求都會重設這個變量。比如:我們可以獲取一些臨時請求的用戶信息。

  • 當調用app = Flask(_name_)的時候,創建了程序應用對象app;
  • request 在每次http請求發生時,WSGI server調用Flask.call();然後在Flask內部創建的request對象;
  • app的生命週期大於request和g,一個app存活期間,可能發生多次http請求,所以就會有多個request和g。
  • 最終傳入視圖函數,通過return、redirect或render_template生成response對象,返回給客戶端。

區別: 請求上下文:保存了客戶端和服務器交互的數據。 應用上下文:在flask程序運行過程中,保存的一些配置信息,比如程序文件名、數據庫的連接、用戶信息等。

上下文對象的作用域

在flask項目中某一個功能中會有多個視圖,那麼from flask import request,current_app,session,g,怎麼保證某次請求的上下文不會被別的視圖拿走呢?

從pycharm中進入globals.py:

_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

線程有個叫做ThreadLocal的類,也就是通常實現線程隔離的類。而werkzeug自己實現了它的線程隔離類:werkzeug.local.Local。LocalStack就是用Local實現的。

LocalStack是flask定義的線程隔離的棧存儲對象,分別用來保存應用和請求上下文。
它是線程隔離的意思就是說,對於不同的線程,它們訪問這兩個對象看到的結果是不一樣的、完全隔離的。這是根據pid的不同實現的,類似於門牌號。

而每個傳給flask對象的請求,都是在不同的線程中處理,而且同一時刻每個線程只處理一個請求。所以對於每個請求來說,它們完全不用擔心自己上下文中的數據被別的請求所修改。


而這個LocalProxy 的作用就是可以根據線程/協程返回對應當前協程/線程的對象,也就是說

  • 線程 A 往 LocalProxy 中塞入 A

  • 線程 B 往 LocalProxy 中塞入 B

無論在是什麼地方,

  • 線程 A 永遠取到得是 A,線程 B 取到得永遠是 B

此處引入:

flask中current_app._get_current_object()與current_app有什麼區別

https://segmentfault.com/q/1010000005865632/a-1020000005865704


查看LocalStack源碼:

def __init__(self):
        self._local = Local()

    def __release_local__(self):
        self._local.__release_local__()

    def _get__ident_func__(self):
        return self._local.__ident_func__

    def _set__ident_func__(self, value):
        object.__setattr__(self._local, '__ident_func__', value)
    __ident_func__ = property(_get__ident_func__, _set__ident_func__)
    del _get__ident_func__, _set__ident_func__

    def __call__(self):
        def _lookup():
            rv = self.top
            if rv is None:
                raise RuntimeError('object unbound')
            return rv
        return LocalProxy(_lookup)

當 app = Flask(__name__) 構造出一個 Flask App 時,App Context 並不會被自動推入 Stack 中。所以此時 Local Stack 的棧頂是空的,current_app 也是 unbound 狀態。

這就說明了爲什麼上下文需要激活狀態,

那麼爲什麼在應用運行時不需要手動 app_context().push() 呢?

因爲 Flask App 在作爲 WSGI Application 運行時,會在每個請求進入的時候將請求上下文推入。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章