• flask上下管理文相关


    RequestContetxt / AppContext对象

    1.flask程序启动时

    当flask程序启动时,通过源码可知,首先会创建两个LocalStack对象,二者内部会分别创建Local对象(上篇文章已经介绍LocalStack)

    from flask import globals
    # 进入globals可以看到如下源码:
    ...
    # context locals
    # 创建
    _request_ctx_stack = LocalStack()
    _app_ctx_stack = LocalStack()
    
    current_app = LocalProxy(_find_app)
    request = LocalProxy(partial(_lookup_req_object, "request"))
    session = LocalProxy(partial(_lookup_req_object, "session"))
    g = LocalProxy(partial(_lookup_app_object, "g"))
    
    

    2.用户请求到来时

    第一步:实例化RequestContext对象,封装数据,得到ctx对象

    当用户请求到来时,执行Flask中的__call__方法,它的作用是将请求相关的数据交由wsgi进行初步封装

    # Flask源码
    class Flask(_PackageBoundObject):
            def __call__(self, environ, start_response):
            return self.wsgi_app(environ, start_response)
    

    wsgi_app方法

    # Flask源码
    class Flask(_PackageBoundObject):
    # wsgi_app封装请求信息
        def wsgi_app(self, environ, start_response):
            # 执行request_context方法,将请求相关的所有数据封装成一个 ctx 对象
            ctx = self.request_context(environ)       
    

    request_context方法

    class Flask(_PackageBoundObject):
            def request_context(self, environ):
            # 实例化RequestContext对象
            return RequestContext(self, environ)
    

    RequestContext对象创建,封装request相关信息,主要是request和session;

    class RequestContext(object):
        def __init__(self, app, environ, request=None, session=None):
            self.app = app
            if request is None:
                request = app.request_class(environ)
            self.request = request
            self.url_adapter = None
            try:
                self.url_adapter = app.create_url_adapter(self.request)
            except HTTPException as e:
                self.request.routing_exception = e
            self.flashes = None
            self.session = session
    

    第二步:将ctx对象通过LocalStack,push到Local中进行保存

    # Flask源码
    class Flask(_PackageBoundObject):
    # wsgi_app封装请求信息
        def wsgi_app(self, environ, start_response):
            # 执行request_context方法,将请求相关的所有数据封装成一个 ctx 对象
            ctx = self.request_context(environ)
            error = None
            try:
                try:
                    ctx.push()
                    response = self.full_dispatch_request()
                except Exception as e:
                    error = e
                    response = self.handle_exception(e)
                except:  # noqa: B001
                    error = sys.exc_info()[1]
                    raise
                return response(environ, start_response)
            finally:
                if self.should_ignore_error(error):
                    error = None
                ctx.auto_pop(error)
    
    
    class RequestContext(object):
            def push(self):
                top = _request_ctx_stack.top
                if top is not None and top.preserved:
                    top.pop(top._preserved_exc)
                # Before we push the request context we have to ensure that there
                # is an application 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()
                    self._implicit_app_ctx_stack.append(app_ctx)
                else:
                    self._implicit_app_ctx_stack.append(None)
    
                if hasattr(sys, "exc_clear"):
                    sys.exc_clear()
    
                _request_ctx_stack.push(self)  
                # 这里的就是通过flask启动时创建的_request_ctx_stack = LocalStack()进行push操作
                ...       
    

    在上述代码中可以看到,执行_request_ctx_stack.push()操作之前,会先对app_ctx对象进行操作

    app_ctx对象

    class Flask(_PackageBoundObject):
    def app_context(self):
    return AppContext(self)

    -  ```python
    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()
          self._refcnt = 0
    
          def push(self):
              """Binds the app context to the current context."""
              self._refcnt += 1
              if hasattr(sys, "exc_clear"):
                  sys.exc_clear()
              _app_ctx_stack.push(self)
              appcontext_pushed.send(self.app)
    
    • 从上述代码中可知,在app_ctx对象中封装的主要是app和g;后通过app_ctx.push()实际上是_app_ctx_stack.push(self)将自己push到Local中

    3.执行视图函数

    full_dispatch_request

    class Flask(_PackageBoundObject):
            def wsgi_app(self, environ, start_response):
                    response = self.full_dispatch_request()
    

    弹出Local中的请求对象

    视图函数执行完毕后,要将Local中的数据进行销毁工作

    class Flask(_PackageBoundObject):
            def wsgi_app(self, environ, start_response):
                finally:
                    if self.should_ignore_error(error):
                        error = None
                    ctx.auto_pop(error)
    

    wsgi源码

        def wsgi_app(self, environ, start_response):
            ctx = self.request_context(environ)
            error = None
            try:
                try:
                    ctx.push()
                    response = self.full_dispatch_request()
                except Exception as e:
                    error = e
                    response = self.handle_exception(e)
                except:  # noqa: B001
                    error = sys.exc_info()[1]
                    raise
                return response(environ, start_response)
            finally:
                if self.should_ignore_error(error):
                    error = None
                ctx.auto_pop(error)
    
  • 相关阅读:
    MySQL——SELECT
    启动 MySQL
    Ethernet and ARP 及Wireshark实验
    ICMP 协议及Wireshark实验
    Wireshark实验——IP 协议
    关键路径
    用树结构存储的图博客(笑)
    拓扑排序
    云计算部署的未来趋势将从自动化转向为自主化
    苹果拥抱 Rust,正在将 C 代码移植到 Rust
  • 原文地址:https://www.cnblogs.com/jjzz1234/p/12037396.html
Copyright © 2020-2023  润新知