• flask中的app context 和 request context


    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

  • 相关阅读:
    环境装好,开始学习
    懒惰了
    我的net试验田
    时间不够用
    【转帖】关于委托的精彩解说(非常形象)
    【转帖】 CLR 全面透彻解析:托管和本机代码互操作性
    【转贴】C#中的API32
    【转帖】Windows Mobile 开发系列文章收藏 Windows Mobile 6.x
    弹跳圣经——扣篮梦
    【转帖】.Net中C#的DllImport的用法
  • 原文地址:https://www.cnblogs.com/geeklove01/p/8544023.html
Copyright © 2020-2023  润新知