Flask备注三(Context)
Flask支持不同的应用场景下,对应不同的local context(本地上下文环境),用来提供当前环境下的资源。lcoal context和全局变量以及局部变量最大的不同在于,作用域是代码范围的,而local context是应用场景范围的。
Flask支持的local context包含application context以及request context。这两个都是线程安全的(基于当前的线程和request), application context存储的是和当前应用程序相关的资源,request context存储的是和当前request相关的资源和信息。
proxies
理解local context之前,首先需要理解flask的proxies。如之前所述,Flask的接口提供了一些常用的全局变量:
- flask.current_app: 当前线程所在的application,flask支持在一个python进程中运行多个app,因此可以通过current_app获取当前所在app。
- flask.request: 当前处理的request,只有在request处理状态可用。
- flask.g: 用来保存状态和资源信息等任何信息。
- flask.session: 当前app的session信息。
上述全局变量都是proxy实现的即:使用这些proxy会访问proxy指向的合适的真实对象。通过这种proxy机制,不同线程使用proxy变量时,代理根据当前的应用场景指向对应线程的变量。因此确保了变量的线程安全,并对最终对象完成了封装(大多数情况下,使用proxy,不需要关心最终对象)。但是下述情况下需要获取proxy对应的最终对象:
- proxy并不会模拟最终对象的类型信息,如果要做示例的类型判断,则需要获取最终对象。
flask的singals需要传递当前application的真是引用,因此要获取最终对象。获取示例如下:
app = current_app._get_current_object()
my_signal.send(app)
proxy指向的对象是线程安全的,并且在不同的应用场景下不同,因此一般储存在application context 和 request context中。
request context
request conetext提供了在request处理时的上线文环境,提供了和request相关的资源。request context提供的资源只能在request处理的线程中使用。在服务器获取request时创建,并在response返回或者exception处理后销毁。
在Flask中维护一个_request_ctx_stack存储所有的request context并维持request context的生命周期。在Flask的通用request处理流程中,request context的实现如下:
通过request_context函数创建request context的对象。
request context的push方法,将request context存储到_request_ctx_stack中。
- 当前request进行处理,将需要的资源存储到request context中。
在request处理完成或者exception处理完成后,request context通过pop方法将request context从_request_ctx_stack中弹出并释放。
程序代码以及第三方扩展都可以修改request context保存需要的资源(更好的方式是将额外的资源存在在application context中)。reqeust context默认提供的资源包含:
- reqeust: 当前的request对象。
- url_adapter: 当前request所使用的url adapter。
- session: 当前的session对象。
- flashes: flash消息的缓存。
application context
application context提供了和当前运行application相关的local context,同样是只在当前request和线程中可用,因此也是线程安全的。生命周期和request context类似,在创建requst context时如果当前线程不存在application context,则同时创建application context。
和request context类似在application context中维护了一个_app_ctx_stack存储所有的app context并维持application context的声明周期。和request conext不同,application context默认提供的资源包含:
- app: 当前线程所在的application,可以通过flask.current_app proxy访问。
- g : 存储用户定义以及第三方扩展需要的资源及属性。
相比于request context,更推荐在application context中存储用户定义以及第三方扩展需要的资源。在local context中存储用户自定义资源必须要明确两点:
- 在context中,进行隐式的存储。(在aplication context中,存储到flask.g中)
- 在context的销毁时,完成资源的销毁。
在local context的自定义的resource,一般通过get_X()函数创建,通过teardown_X()函数销毁,其中teardown_X()函数必须注册为application context或者request context的handler。示例如下:
import sqlite3
from flask import g
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = connect_to_database()
return db
@app.teardown_appcontext
def teardown_db(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
同样,和其他的proxy一样,可以将这个资源声明为LocalProxy。
from werkzeug.local import LocalProxy
db = LocalProxy(get_db)
这样我们可以通过db来访问get_db函数。