一、问题引出

    当在测试文件里直接要获得flask核心对象app时(即不启动服务器),按照下面的方式会报出error,如下图

看似和平时获得app对象没有什么不同,但是这种方法是获取不到的,这就引出了flask中的上下文机制。

二、flask的上下文机制

1.flask中存在应用上下文(AppContext)和请求上下文(RequestContext),flask的核心对象被存储在AppContext应用上下文中,即AppContext是对flask核心对象app进行了封装;项目中的请求信息Request会被存储在RequestContext请求上下文中

2.通过阅读源码可以看到,这两个上下文对象都存在push()、pop()、enter()、exit()四个方法。

(1)根据上图,当一个请求进入我们的flask项目中,flask框架会实例化一个RequestContext对象,这次请求的相关信息Request被封装在RequestContext里,准备压入栈中(即push操作)。在flask中,栈是通过LocalStack这个对象实现的,实例化LocalStack这个对象并赋给_request_ctx_stack。

(2)当要把RequestContext压入栈之前,flask会检查   _app_ctx_stack这个栈中是否有值,如果该栈为空,那么flask会再实例化一个AppContext对象,封装了核心对象app,压入_app_ctx_stack这个栈中(也就是说,如果请求到达,_app_ctx_stack中没有值,那么flask会先将AppContext封装当前对象先压栈,再将RequestContext压栈)注意入栈先后顺序

(3)如果我们在运行项目时,上图中current_app和request这两个proxy都是指向上面所说的两个栈的栈顶,如果栈顶有值的情况下,那么就不会出现文章开头的Working outside of application context 错误了

三、问题解决

如上所述,出现这种错误的原因就是_app_ctx_stack这个栈的栈顶没有元素,那么我们可以手动创建一个app将其压入栈中

法一:利用app_context()方法

法二:利用with语句

四、深入理解

        在上面提到过,flask的两个上下文对象都实现了四个方法(push,pop,enter,exit)。在python中,实现了enter和exit这两个方法的对象也就是实现了上下文协议,而实现了上下文协议的对象又称作上下文管理器,所以,AppContext和RequestContext这两个对象在flask中都可以称作上下文管理器。那么我们也可以自己实现一个上下文管理器并用with语句测试一下:

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐