1
Working outside of application context
Working outside of application context.是在flask中出现的经典错误。如下这段代码,就会出现 Working outside of application context.
from flask import Flask, current_app
app = Flask(__name__)
a = current_app
d = current_app.config['DEBUG']
2
Flask的上下文对象
Flask有两种Context(上下文),分别是 请求上下文 和应用上下文。
RequestContext 请求上下文 包括:
-
Request 请求的对象,封装了Http请求(environ)的内容
-
Session 根据请求中的cookie,重新载入该访问者相关的会话信息。
AppContext 应用上下文 包括:
-
g 处理请求时用作临时存储的对象。每次请求都会重设这个变量
-
current_app 当前激活程序的程序实例
生命周期:
-
current_app的生命周期最长,只要当前程序实例还在运行,都不会失效。
-
Request和g的生命周期为一次请求期间,当请求处理完成后,生命周期也就完结了。
-
Session就是传统意义上的session了。只要它还未失效(用户未关闭浏览器、没有超过设定的失效时间),那么不同的请求会共用同样的session。
3
核心机制
阅读源码文件 globals.py
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
LocalStack是由Werkzeug库提供的一个线程隔离的栈结构,可以将对象推入、弹出, 也可以快速拿到栈顶对象。图为核心机制的原理图,当一个请求进入flask,首先检查_app_ctx_stack中有没有元素,如果栈顶元素是空或者不是当前的对象。那么会先推入AppContext,然后再推入RequestContext。而requext(Local Proxy) current_app(Local Proxy) 始终指向栈顶的元素,如果栈顶是空,就会出现unbound。这就是出现Working outside of application context.的原因。那么,说明只要手动将AppContext推入栈中,就不会出现一样的问题。
from flask import Flask, current_app
app = Flask(__name__)
# 获取应用上下文
ctx = app.app_context()
# 将应用上下文推入栈中
ctx.push()
a = current_app
d = current_app.config['DEBUG']
# 出栈
ctx.pop()
运行如下代码,则不会再出现同样问题。那么在视图函数中,为什么不需要手动推入?
因为 Flask App 在作为 WSGI Application 运行时,会在每个请求进入的时候将请求上下文推入 _request_ctx_stack 中,而请求上下文一定是 App 上下文之中,所以推入部分的逻辑有这样一条:如果发现 _app_ctx_stack为空,则隐式地推入一个 App 上下文。所以,请求中是不需要手动推上下文入栈的。