Flask请求上下文

Flask请求上下文

# 说实话,当时看完视频知道怎么回事。就是容易忘.....
# 不过总不能一直看视频对吧,尽快理解和掌握吧....惭愧啊

预备知识

1. werkzeug

当我们下载flask模块时该模块也会被下载,那么该模块有什么用处呢?
我们看下面的代码
from werkzeug.wrappers import Response, Request
from werkzeug.serving import run_simple


@Request.application
def app(req):
    print(req)
    print(req.method)
    print(req.path)
    return Response("200 OK!")


run_simple(hostname="127.0.0.1", port=8800, application=app)

  • 看运行结果

    image-20210904202832523

  • 是不是很好奇?它怎么会有request对象

    这些我们暂且不讨论,当我们运行run_simple时,是不是相当于执行了app函数 ---> app()
    (可能你不知道现在在干什么,往下看)
    

2. 线程安全

.....

3. partial

  • 偏函数

  • 示例

    from functools import partial
    
    
    def ab(a, b):
        print(a)
        return a + b
    
    # 第一个参数为对象,后面可以指定参数: a=1, b=2
    new_ab = partial(ab, a = "request", b="200 OK!")  
    new_ab = partial(ab, "request")  
    
    # 指定后就不需要再传参了
    # print(new_ab())
    print(new_ab("200 OK!"))
    

    image-20210904220613914

请求上下文

1. 请求上文

  • flask实例

    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route("/")
    def index():
        return "123"
    
    if __name__ == '__main__':
        app.run()  # 进去看run源码
    
    • run方法

      	.....省略.....
      from werkzeug.serving import run_simple  # 熟悉吧,就刚刚的
      
      # 我们就可以继续引申我们的flask的app实例运行时,也可以说是这样执行了app实例:通过对象()方式执行
      try:
          # flask实例也是通过run_simple运行起来的,也就是说执行时是 flask实例+()执行
          # 但实例+()怎么执行呢? __call__方法啊。想起来了不
          run_simple(host, port, self, **options)  
      finally:
          self._got_first_request = False
      
    • 也就是说,flask实例执行__call__方法
      from flask import Flask, request
      
      app = Flask(__name__)
      
      
      @app.route("/")
      def index():
          return "123"
      
      if __name__ == '__main__':
          app.run()  # 进去看run源码
          app.__call__  # 继续进去看源码
      
    • call方法

          def __call__(self, environ, start_response):  # self = app = Flask(), environ为请求原始信息
              """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方法

      def wsgi_app(self, environ, start_response):  self = app = Flask()
          # 最终返回一个RequestContext(),含有request、session属性(从environ --> 请求原始信息中取出的)
          ctx = self.request_context(environ)  
          # ctx = RequestContext(..)  ctx含有request、session属性
          error = None
          try:
              try:
                  ctx.push() # request_context.push()
          ..... 省略 ....
          
      

      image-20210904205346824

    • 继续看ctx.push()

      def push(self): # self = ctx = RequestContext() = (request,session)
          top = _request_ctx_stack.top # 这里先直接过,是None
          # 不执行
          if top is not None and top.preserved:  
              top.pop(top._preserved_exc)
       	..... 省略 ....
          _request_ctx_stack.push(self)  # self = ctx(request,session)
      
    • request_ctx_stack.push(self),我们要先知道 request_ctx_stack

      _request_ctx_stack = LocalStack()  # 将该类进行实例化 
      
      def __init__(self):
          self._local = Local()  # 继续实例化Local
      
      class Local(object):
          __slots__ = ("__storage__", "__ident_func__")
      
          def __init__(self):
              # 设置属性
              object.__setattr__(self, "__storage__", {})
              # get_ident是一个函数,是为了获取线程id,看预备知识
              object.__setattr__(self, "__ident_func__", get_ident) # 线程id
              
              
      # Local = {"__storage__":{},"__ident_func__":get_ident}  是一个对象(就是为了看起来方便,不是一个字典)
      
    • 最终也就是说

      _request_ctx_stack = LocalStack() 
      # LocalStack()该实例化属性含有_local属性
      # _local = {"__storage__":{},"__ident_func__":get_ident}
      
      _request_ctx_stack = LocalStack() -->   # ._local >>> {"__storage__":{},"__ident_func__":get_ident}
      
    • 继续回到_request_ctx_stack.push(self),看push方法

      def push(self, obj): # obj = ctx = (request,session), self = _request_ctx_stack = LocalStack() 
          # _local >>> {"__storage__":{},"__ident_func__":get_ident}
          rv = getattr(self._local, "stack", None)
          if rv is None:
              self._local.stack = rv = []  # .stack = xx,没有该属性,执行setattr方法
           # 可能涉及拷贝,对rv操作就对字典中的[]也进行了操作
           rv.append(obj)
           # {"__storage__":{9527:{stack:[ctx(request,session)]}},"__ident_func__":get_ident}
           return rv  # {9527:{"stack":[ctx(request,session)]}}
      
      def __setattr__(self, name, value):  # name = stack, value = []
          ident = self.__ident_func__()  # 获取线程id,假设为9527
          storage = self.__storage__  # 获取到一个 空{}
          try:
              storage[ident][name] = value  # storage = {ident:}
          except KeyError:
              
              storage[ident] = {name: value} # storage = {9527:{"stack:[]}}
      

2. 请求下文

  • 需要用到上面的 partial

  • flask实例

    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route("/")
    def index():
        print(request)  # 点进去看源码
        print(request.method)
        return "123"
    
    if __name__ == '__main__':
        app.run()  # 进去看run源码
    
    • request:

      request = LocalProxy(partial(_lookup_req_object, "request"))  # 将request作为参数传入
      
    • _lookup_req_object

      def _lookup_req_object(name):  # name = request
          # 这里省了一点步骤,你可以继续点进top,记得有时候需要getattr或者setattr
          top = _request_ctx_stack.top   # _request_ctx_stack = [ctx(request,session)]
           # top = ctx(request,session) = RequestContext(),里面含有request、session等属性
          if top is None:
              raise RuntimeError(_request_ctx_err_msg)
          # 从ctx获取request属性
          return getattr(top, name)
      
      
    • 该偏函数执行后返回一个request对象(该对象就是request自身)

  • 从request获取属性,例如method

    request.method
    # 没有该属性,执行LocalProxy中的__gatattr__方法,先进行实例化再执行__gatattr__方法
    
    request = LocalProxy(partial(_lookup_req_object, "request"))  # 将request作为参数传入
    
  • 实例化

    def __init__(self, local, name=None): # local就是偏函数partial,偏函数执行可以获取request真身
        object.__setattr__(self, "_LocalProxy__local", local)
        object.__setattr__(self, "__name__", name)
        # 判断该偏函数是否可以执行和是否不含有__release_local__属性,成立!!!
        if callable(local) and not hasattr(local, "__release_local__"):
            object.__setattr__(self, "__wrapped__", local)  # 设置属性
    
  • 执行__gatattr__方法

    def __getattr__(self, name):  # name = method, form ...
        if name == "__members__":
            return dir(self._get_current_object())
        # 从某个对象中执行getattr方法,执行self._get_current_object()方法获取对象
        return getattr(self._get_current_object(), name)  
    
  • 执行_get_current_object()方法

    def _get_current_object(self):
        # 看实例化:object.__setattr__(self, "_LocalProxy__local", local),设置类的私有属性值
        if not hasattr(self.__local, "__release_local__"):  
            # 获取私有属性,该私有属性值为local,也就是偏函数
            return self.__local() # 执行偏函数,获取request真身
        try:
            return getattr(self.__local, self.__name__)
        except AttributeError:
            raise RuntimeError("no object bound to %s" % self.__name__)
    
  • 结束:

    def __getattr__(self, name):  # name = method, form ...
        if name == "__members__":
            return dir(self._get_current_object())
        # 从某个对象中执行getattr方法,执行self._get_current_object()方法获取对象
        return getattr(self._get_current_object(), name)   # 从request中获取method等属性
    

简单总结

image-20210904224512893

posted @ 2023-03-05 12:35  w随风w  阅读(26)  评论(0编辑  收藏  举报