当前位置:   article > 正文

flask中的app context 和 request context

flask 的requestcontext 和appcontext有什么区别

app context,应用上下文,存储的是应用级别的信息,比如数据库连接信息。

request context,程序上下文,存储的是请求级别的信息,比如当前访问的url

 

按照官方文档,有两种方式创建一个app context:
一是当一个请求到来,这时候request context创建,app context也随之创建

二是显式使用 app_context 方法,如下:

from flask import Flask, current_app

app = Flask(__name__)
with app.app_context():
    # within this block, current_app points to app.
    print current_app.name

下面跟随代码,看第一种创建是如何实现的。

我们知道,一个典型的flask app是这样开始运行的:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run()

这时候,app是在特定端口监听请求。

当一个请求过来的时候,跟随代码可以知道,会调用Flask class的__call__方法来创建响应

call的时候,执行如下代码:

    def wsgi_app(self, environ, start_response):
        ctx = self.request_context(environ)
        ctx.push()
        error = None
        try:
            try:
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)

在执行 ctx.push() 的时候,创建了 app context,如下所示:

        app_ctx = _app_ctx_stack.top
        if app_ctx is None or app_ctx.app != self.app:
            app_ctx = self.app.app_context()
            app_ctx.push()
     ......

     _request_ctx_stack.push(self)

调用 self.app.app_context() 的时候,将之前Flask创建的app作为参数传入到 AppContext 类里。

app_ctx.push() 的时候,将返回的app_ctx对象放到 _app_ctx_stack 这个stack上

显然,这里的app中包含了许多应用层面的信息。可以在flask.app.py:Flask这个类中看到。

比如 default_config 这个ImmutableDict中就包含了诸如 SECRET_KEY,JSONIFY_MIMETYPE这些应用层面的信息。

 

随后调用 _request_ctx_stack.push(self),将RequestContext对象放到_request_ctx_stack这个stack上

那么这个RequestContext对象(也就是上文wsgi_app方法中的ctx)中包含什么呢?

一路跟上去,发现初始化ctx对象的environ是从werkzeug.serving.py:WSGIRequestHandler:make_environ

这个方法得到的,这里面都是一些与请求相关的信息,比如:QUERY_STRING,REQUEST_METHOD,REMOTE_PORT等等。

示例:https://www.toptal.com/python/pythons-wsgi-server-application-interface

 

有一个问题,为什么要区分app context和request context?原因如下:

1 首先概念上,逻辑上讲,在request未到来之前,app处于app context,当request到来之后,request context被创建。

 app context用于存储数据库链接等与app相关的信息,request context用于存储和request相关的信息。

 这是一个很自然的想法

2 flask允许多app并用(http://flask.pocoo.org/docs/0.12/patterns/appdispatch/),

request需要不同的app context来区分自己正在那个app上请求

3 测试的时候(这是一种在非web环境运行Flask代码的情况,一般只在主线程进行),离线脚本只需要app关联的上下文,

不需要构造请求,此时只需要app context,不需要 request context,所以需要区分

一个来自stackoverflow的例子:

app = Flask(__name__)
db = SQLAlchemy() # Initialize the Flask-SQLAlchemy extension object
db.init_app(app)

在这种情况下,初始化、测试db的时候只需要一个app context就行了,不需要request context

为什么用stack来存储app context和request context?

首先,为什么request context设计成stack的形式?

flask请求中有redirect的情况。

比如当请求a的时候,a需要再请求b,这时就可以把请求push,处理b的请求之前把与b有关的请求信息push,等请求完b再处理a

显然stack最合适

app context为什么设计成stack的形式?

前文已经解释过,既然flask允许多个app并存,当request在不同的app context之间游走的时候,用stack记录哪个是“当前”自然是最好的

一旦脱离了某个app context的范围,app context自然就出栈了

一个源自官网的例子:

from flask import Flask, current_app

app = Flask(__name__)
with app.app_context():
    # within this block, current_app points to app.
    print current_app.name

 

 ref: http://cizixs.com/2017/01/13/flask-insight-context

https://blog.tonyseek.com/post/the-context-mechanism-of-flask/

http://flask.pocoo.org/docs/0.12/appcontext/

https://stackoverflow.com/questions/20036520/what-is-the-purpose-of-flasks-context-stacks/20041823#20041823

 

转载于:https://www.cnblogs.com/geeklove01/p/8544023.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/501430
推荐阅读
相关标签
  

闽ICP备14008679号