zoukankan      html  css  js  c++  java
  • Flask上下文管理

    主要内容

    • 1. Flask 请求上下文管理
    • 2. Flask 应用上下文管理

    1. Flask请求上下文管理

    1.1 Flask请求上文

    • 当请求进来时,app(), Flask实例化对象app执行__call__
          def __call__(self, environ, start_response):
              """The WSGI server calls the Flask application object as the
              WSGI application. This calls :meth:`wsgi_app` which can be
              wrapped to applying middleware."""
              return self.wsgi_app(environ, start_response)
    • 执行wsgi_app  得到 一个 RequestContext的对象 ctx (封装了request以及session)
      ctx = self.request_context(environ)
      class RequestContext(object):
          #此时的self是RequestContext对象 -->ctx 中封装了request/session
          def __init__(self, app, environ, request=None):
              self.app = app      #app = Flask对象
              if request is None:
                  #请求的原始信息通过request_class后此时request已经存在,request.methods等
                  request = app.request_class(environ)
              self.request = request
              self.url_adapter = app.create_url_adapter(self.request)
              self.flashes = None
              self.session = None
    • ctx 执行 ctx.push(): 
      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)
    • RequestContext对象的push方法 
          def push(self):
              # _request_ctx_stack = LocalStack()一个LocalStack对象
              # _request_ctx_stack._local = LocalStack()._loacl = {"__storage__":{},"__ident_func__":get_ident}
              top = _request_ctx_stack.top
              #top =None
              if top is not None and top.preserved:
                  top.pop(top._preserved_exc)

      _request_ctx_stack是一个LocalStack对象 ,LocalStack()._local是一个Local对象 即Local()

      class LocalStack(object):
          def __init__(self):
              self._local = Local()
              #self._loacl = {"__storage__":{},"__ident_func__":get_ident}

      Local对象经过初始化得到的字典值

      class Local(object):
          #限定当前只能由两个属性值
          __slots__ = ('__storage__', '__ident_func__')
      
          def __init__(self):
              object.__setattr__(self, '__storage__', {})
              object.__setattr__(self, '__ident_func__', get_ident)
      
              # {"__storage__":{},"__ident_func__":get_ident}  #此时get_dient 是个没有执行的函数,内存地址

      _request_ctx_stack中top方法,返回None

          @property
          def top(self):
              """The topmost item on the stack.  If the stack is empty,
              `None` is returned.
              """
              try:
                  # self._local 即Local对象调用__getattr__方法
                  #在下文时候Local对象{"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident}
                  # [ctx->request/session]
                  return self._local.stack[-1]
                  #得到ctx对象
              except (AttributeError, IndexError):
                  return None

      _request_ctx_stack 对象执行push方法

              #当前的self为ctx
              _request_ctx_stack.push(self)
          def push(self, obj):
              #此时的self是LocalStack对象, obj为ctx
              """Pushes a new item to the stack"""
              # self._local = {"__storage__":{},"__ident_func__":get_ident}
              #找不到返回值是None
              rv = getattr(self._local, 'stack', None)
              if rv is None:
                  #由于.stack后面有等号,执行的时候Local()对象的__setattr__方法
                  #实际上是地址的赋值,此时stack和rv都指向空列表
                  self._local.stack = rv = []
                  #{"__storage__":{8080:{stack:rv=[]}},"__ident_func__":get_ident}
              rv.append(obj)
              # {"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident}
              # 应用上下文时候{"__storage__":{8080:{stack:rv=[app_ctx->(app/g)]}},"__ident_func__":get_ident}
              return rv
              #rv=[ctx->request/session]
          def __setattr__(self, name, value):
              #name=stack   value=rv=[]
              #self是Local对象 {"__storage__":{},"__ident_func__":get_ident}
              ident = self.__ident_func__() #执行get_ident函数获取当前线程id 8080
              storage = self.__storage__  #storge ={8080:{stack:rv=[]}}
              try:
                  storage[ident][name] = value
              except KeyError:
                  storage[ident] = {name: value}   #storage={}
      
               # {"__storage__":{8080:{stack:rv=[]}},"__ident_func__":get_ident}
    • 执行完push方法 请求上文结束:
      #当请求进来,第一件事就是要把当前这个请求在我服务器上的线程开辟一个空间(线程对应的空间,必须含有stack对应一个列表存放ctx(request/session)
      # {"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident}

    1.2 Flask请求下文

    • 导入request开始使用,在request中
      #此时request是一个函数包裹一个偏函数   LocalProxy()是一个代理
      #当前的request是一个LocalProxy()  request.method  执行__getattr__方法
      request = LocalProxy(
          partial(_lookup_req_object, 'request')   #return request对象
      )
    • 在偏函数中 将request传入到 _lookup_req_object中: 此时得到一个request对象
      def _lookup_req_object(name):
          # _request_ctx_stack是LocalStack对象
          top = _request_ctx_stack.top
          #下文[ctx->request/session]
          if top is None:
              raise RuntimeError(_request_ctx_err_msg)
          #此时的name是request,从ctx对象中找出request对象
          return getattr(top, name)
          @property
          def top(self):
              """The topmost item on the stack.  If the stack is empty,
              `None` is returned.
              """
              try:
                  # self._local 即Local对象调用__getattr__方法
                  #在下文时候Local对象{"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident}
                  # [ctx->request/session]
                  return self._local.stack[-1]
                  #得到ctx对象
              except (AttributeError, IndexError):
                  return None

      此时的top不是None已经存在值

    • partial(_lookup_req_object, 'request') 这一层执行完得到一个reauest对象,将偏函数传入到LocalProxy中

      @implements_bool
      class LocalProxy(object):
          __slots__ = ('__local', '__dict__', '__name__', '__wrapped__')
      
          def __init__(self, local, name=None):
              #local是request偏函数
              object.__setattr__(self, '_LocalProxy__local', local)   #__local = request偏函数
              object.__setattr__(self, '__name__', name)
              #当前偏函数可以执行而且判断loacl中是否有 __release_local__  ==>这句话成立
              if callable(local) and not hasattr(local, '__release_local__'):
                  # "local" is a callable that is not an instance of Local or
                  # LocalManager: mark it as a wrapped function.
                  object.__setattr__(self, '__wrapped__', local)  #__warpped__还是local偏函数
    • 当前的request是一个LocalProxy() request.method 执行LocalProxy中的__getattr__方法

          def __getattr__(self, name): # name是method(举例)
              if name == '__members__':
                  return dir(self._get_current_object())
              #此时self._get_current_object()是经过_local 执行后得到的request对象,从request对象中去取出method
              return getattr(self._get_current_object(), name)
          def _get_current_object(self):
              #self._local是偏函数
              if not hasattr(self.__local, '__release_local__'):
                  #执行偏函数,返回request对象
                  return self.__local()
              try:
                  return getattr(self.__local, self.__name__)
              except AttributeError:
                  raise RuntimeError('no object bound to %s' % self.__name__

    2. Flask 应用上下文管理

    • 执行wsgi_app方法
         #ctx为一个RequestContext的对象,参数为environ
              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)
    • 执行push方法,_app_ctx_stack 同样是LocalStck对象,初始化时候top为None
          def push(self):
              app_ctx = _app_ctx_stack.top
              #app_ctx = None
              if app_ctx is None or app_ctx.app != self.app:
                  app_ctx = self.app.app_context()   #app_context是AppContext对象  与RequestContenx一样,知识序列化出app和g
                  app_ctx.push()
                  # 应用上文时候{"__storage__":{8080:{stack:rv=[app_ctx->(app/g)]}},"__ident_func__":get_ident}
                  self._implicit_app_ctx_stack.append(app_ctx)
              else:
                  self._implicit_app_ctx_stack.append(None)

      执行app_ctx.push  进而 _app_ctx_stack.push

         def push(self):
              """Binds the app context to the current context."""
              self._refcnt += 1
              if hasattr(sys, 'exc_clear'):
                  sys.exc_clear()
                  #将AppContext存在LocalStack对象中
              _app_ctx_stack.push(self)
              appcontext_pushed.send(self.app)
          def push(self, obj):
              #此时的self是LocalStack对象, obj为ctx
              """Pushes a new item to the stack"""
              # self._local = {"__storage__":{},"__ident_func__":get_ident}
              #找不到返回值是None
              rv = getattr(self._local, 'stack', None)
              if rv is None:
                  #由于.stack后面有等号,执行的时候Local()对象的__setattr__方法
                  #实际上是地址的赋值,此时stack和rv都指向改空列表
                  self._local.stack = rv = []
                  #{"__storage__":{8080:{stack:rv=[]}},"__ident_func__":get_ident}
              rv.append(obj)
              # {"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident}
              # 应用上下文时候{"__storage__":{8080:{stack:rv=[app_ctx->(app/g)]}},"__ident_func__":get_ident}
              return rv
              #rv=[ctx->request/session]

      到此,push完毕,应用上文结束,应用下文在离线脚本时候使用

    另外:在global.py中

    def _find_app():
        top = _app_ctx_stack.top    #得到app_ctx(app / g)
        if top is None:
            raise RuntimeError(_app_ctx_err_msg)
        return top.app  #返回一个app即flask对象 只不过此时的flask对象 是公共的,与初始化的相同
        # 但是是独立出来已经被配置好的Flask对象
    
    # LocalStack是 针对当前这个线程对独立的Flask_app进行修改, 不影响现在运行的app  =>离线脚本
    #但是这个app 在请求结束后会从LocalStack中通过 __delattr__ 删除
    
    
    # context locals
    _request_ctx_stack = LocalStack()  #LocalStark = self._loacl = {"__storage__":{},"__ident_func__":get_ident}
    _app_ctx_stack = LocalStack()
    current_app = LocalProxy(_find_app)   # current_app可以点 .run |  .route 等
  • 相关阅读:
    MyBatis的初始化方式
    WCF X.509验证
    NPOI导出EXCEL 打印设置分页及打印标题
    一些旁门左道
    曲线救国:IIS7集成模式下如何获取网站的URL
    图片的粘贴上传
    让EF飞一会儿:如何用Entity Framework 6 连接Sqlite数据库
    ASP.NET 保存txt文件
    JavaScript高级程序设计学习笔记--高级技巧
    JavaScript高级程序设计学习笔记--错误处理与调试
  • 原文地址:https://www.cnblogs.com/wcx666/p/10451883.html
Copyright © 2011-2022 走看看