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è)appdb.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)從源碼中解決問題
