Flask核心机制:current_app
请求上下文流程
flask的request对象是一个全局对象,跟django的request不太一样,django的request对象是每次请求一个,但是flask全局就一个request对象,但是每次请求它能区分开是哪个请求,这个做的挺牛逼的,我去看了一下它的源码,原来是写了一个local类,来处理不同线程,每一个线程都用自己的reqeust对象,这样保证了使用的时候没有乱。
请求上下文是ctx对象,内部有request和session对象
应用上下文是app_ctx内部有g和app对象
核心知识
AppContext手动、自动入栈
LocalStack是线程隔离的栈结构
current_app是线程、协程隔离对象
LocalProxy是获取当前线程隔离的代理对象
AppContext、RequestContext、Flask与Request之间的关系
AppContext
应用上下文,是对flask一切对象的封装
RequestContext
请求上下文,是对request请求对象的封装
current_app
类型是LocalProxy
像全局变量一样工作,但只能在处理请求期间且在处理它的线程中访问
返回的栈顶元素不是应用上下文,而是flask的应用实例对象
应用上下文的封装=flask核心对象+和外部协作对象(再flask封装对象上再添加push、pop等)(请求上下文同理)
详解flask上下文与出入栈
flask在RequestContext入栈前会检查另外一个AppContext的栈的情况,如果栈顶元素为空或者不是当前对象,就会把AppContext推入栈中,然后RequestContext才进栈。
LocalStack作用是线程隔离
LocalProxy 的作用就是可以根据线程/协程返回对应当前协程/线程的代理对象,也就是说
线程 A 往 LocalStack中塞入 A
线程 B 往 LocalStack 中塞入 B
无论在是什么地方,调用LocalProxy,
线程 A 永远取到得是 A,线程 B 取到得永远是 B
有关Local、LocalStack的详解可以参考:http://python.jobbole.com/87738/
这就是在 Flask 中可以在代码中直接使用 request、current_app 这样的变量的底层原因。
应用上下文
与请求上下文类似,当请求进来时,先实例化一个AppContext对象app_ctx,在实例化的过程中,提供了两个有用的属性,一个是app,一个是g。self.app就是传入的全局的app对象,self.g是一个全局的存储值的对象。接着将这个app_ctx存放到LocalStack()。
class AppContext(object):
def init(self, app):
self.app = app
self.url_adapter = app.create_url_adapter(None)
self.g = app.app_ctx_globals_class()
视图函数中,我们就可以调用app对象和g对象,如果我们使用蓝图构建我们的项目时,在每一个直接引用app就会造成循环引用的异常,这时,应用上下文就会显得非常有用,我们可以直接调用current_app就可以在整个生命周期中使用我们的app对象了。比如使用我们的配置项:current_app.config
current_app = LocalProxy(_find_app)
最后,当视图函数执行结束后,从storage中pop掉app_ctx对象。
from flask import Flask,request,session,g
app = Flask(__name__) # type:Flask
@app.before_request
def auth_demo():
g.val = 123
@app.route('/')
def index():
print(g.val)
return "Hello World"
if __name__ == '__main__':
app.run()
总结:flask中的上下文管理机制分为请求上下文和应用上下文两大方面,通过上下文的管理机制,实现了即去即用的一个特色。