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 @   w随风w  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示