Python flask核心機(jī)制

from flask import Flask, current_app

app = Flask(__name__)

a = current_app

d = current_app.config['DEBUG']
  • flask中的經(jīng)典錯(cuò)誤 woring outside application context,這個(gè)錯(cuò)誤出現(xiàn)的原因在于flask的上下文機(jī)制

  • flask中的上下文

    • 應(yīng)用上下文AppContext 對(duì)象 對(duì)核心對(duì)象Flask的封裝

    • 請(qǐng)求上下文RequestContext 對(duì)象 對(duì)Request的封裝

    • 當(dāng)一個(gè)請(qǐng)求進(jìn)入到框架之后,flask首先會(huì)實(shí)例化一個(gè)RequestContext對(duì)象,它封裝了請(qǐng)求信息,flask是編寫web應(yīng)用的,所以我們要探討flask是如何應(yīng)用兩個(gè)上下文的必須從一個(gè)請(qǐng)求進(jìn)入flask框架開始

    • RequestContext會(huì)推入到_request_ctx_stack中,在入棧之前flask會(huì)去檢查另外一個(gè)棧_app_ctx_stack中的棧頂元素,如果這個(gè)棧頂元素是空或者不是當(dāng)前對(duì)象,那么flask會(huì)將AppContext推入到_app_ctx_stack中,然后才會(huì)將RequestContext推入_request_ctx_stack棧中

    • current_app和request永遠(yuǎn)是指向棧頂?shù)?,是運(yùn)用了代理模式,在代理的時(shí)候,其實(shí)就是間接的在操作兩個(gè)棧的棧頂元素

    • 注意:Current_app是flask的核心對(duì)象,他是取了棧頂元素AppContext的app屬性,request也是同樣的道理,request也是Request屬性

    • 當(dāng)請(qǐng)求結(jié)束是,兩個(gè)棧中的元素會(huì)被彈出

from flask import Flask, current_app

app = Flask(__name__)

ctx = app.app_context()  # 得到應(yīng)用上下文的對(duì)象

ctx.push()

a = current_app

d = current_app.config['DEBUG']

ctx.pop()
  • 在請(qǐng)求中不用手動(dòng)的推入,flask已經(jīng)幫我們推入了,當(dāng)你寫離線應(yīng)用或者是單元測(cè)試的時(shí)候,需要手動(dòng)推入

  • with語句

    • 實(shí)現(xiàn)了上下文協(xié)議的對(duì)象使用with,這種對(duì)象我們通常稱為上下文管理器

    • 實(shí)現(xiàn)了__enter__,__exit__

    • 上下文表達(dá)式必須返回一個(gè)上下文管理器,with后面的變量叫做上下文表達(dá)式

    • As后面的變量一定不是上下文管理器,而是上下文管理器的enter方法所返回的值

class A:

    def __enter__(self):

        a = 1

        #return a

    def __exit__(self):

        b = 2

with A() as obj_a:   # 這里的obj_a值為None,

    # 這里要靈活一下,上下文表達(dá)式必須要返回一個(gè)上下文管理器并不一定要用函數(shù)的形式返回,實(shí)例化也可以

    pass
  • exit方法
class MyResource:

    def __enter__(self):

        print('connect to resource')

        return self

    def __exit__(self, exc_type, exc_val, exc_tb):

        """

        回收資源,或者是處理異常,后面的三個(gè)參數(shù)是處理異常的時(shí)候使用

        :param exc_type:異常類型

        :param exc_val:異常的值

        :param exc_tb:異常信息

        :return: 默認(rèn)返回的是False

            True: with語句的外部不會(huì)再拋出異常

            False: 當(dāng)with語句執(zhí)行完成之后,with的外部還會(huì)再次拋出異常

        """

        if exc_tb:

            print('process exception')

        else:

            print('no exception')

        print('close resource connection')

        return False

    def query(self):

        print('query data')

try:

    with MyResource() as resource:

        resource.query()

except Exception as ex:

    pass
  • db.init_app(app) db.create_all(app=app)

  • 為什么要兩次傳入app呢,是因?yàn)樵趇nit_app中沒有保存app這個(gè)變量,而是當(dāng)做了一個(gè)臨時(shí)參數(shù)使用的,所以db.create_all也需要找到一個(gè)app

  • db.create_all怎么找到app呢,

    • 方案一,傳入一個(gè)關(guān)鍵字參數(shù)app

    • 方案二,current_app有值,也就是將應(yīng)用上下文推入到棧中

with app.app_context():

    db.create_all()
  • 方案三,在構(gòu)造函數(shù)中傳入,db = SQLAlchemy(app)

  • 從源碼中解決問題

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容