Flask上下文管理

1、一些python的知识

一、偏函数

复制代码
def add(x, y, z):
    print(x + y + z)


# 本来的写法:x,y,z能够传任意数字
add(1,2,3)


# 若是我要实现一个功能,这三个数中,其中一个数必须是3
# 咱们就可使用偏函数来帮着咱们传参
from functools import partial

# partial:给add这个函数固定传一个数字 3
new_add = partial(add, 3)

# 所以新的函数只须要传2个参数
new_add(1,1)
new_add(1,2)


# 偏函数:就是帮咱们给一个函数固定一个参数
# new_add(x1, x2) --> add(3, x1, x2)
复制代码

 

二、类的两个双下方法

复制代码
1. __getattr__:对象获取属性值的时候触发

2. __setattr__:对象设置属性值的时候触发

3.示例
class A(object):
    def __init__(self):
        # self.name = {}
        # 初始化的时候,给这个对象设置一个属性名为name,值为空的字典
        object.__setattr__(self, "name", {})

    def __getattr__(self, item):
        print("getattr: ", item)

    def __setattr__(self, key, value):
        print("setattr: ", self.name)
        print("setattr: ", key, value)
        self.name[key] = value
        print("setattr: ", self.name)


# 实例化,调用__init__
a = A()

# 获取对象某个属性的值,会调用__getattr__
# 若是A这个类没有__getattr__,就会去执行父类的__getattr__
# 可是严谨的__getattr__是:若是你没有这个属性,就会给你报错
# 咱们能够在A类重写__getattr__,可让它不报错
a.xxx  # getattr:  xxx

# 给对象的某个属性设置值,会调用__setattr__
# 执行的逻辑跟__getattr__同样,A类没有就去调用父类的
a.xxx = '小明'
# 首先打印name字典的默认值:是个空字典 setattr:  {}
# setattr的key是左边的变量,value是右边的值:setattr:  xxx 小明
# 打印self.name这个字典:setattr:  {'xxx': '小明'}
复制代码

 

2、Flask上下文管理

Flask的上下文管理咱们能够理解为一个生命周期
也就是请求进来到请求出去一共作了哪些事情
首先咱们知道项目启动执行了app.run()方法,调用了werkzeug的run_simple()方法
run_simple(host, port, self, **options) 这时候的self就是咱们的app
run_simple会执行self(),也就是app(), 那么app = Flask() 因此会走Flask的__call__方法前端

那么__call__作了什么呢

environ是咱们请求来的原始数据~当成参数传递给了request_context方法python

 


进入这个RequestContext对象flask

 


这是初始化这个类作的一些事情
在这里从新封装了request, 以及给session 赋值了 None
也就是说:
ctx = RequestContext(app, environ)
ctx.request 是从新封装的request
ctx.session = Nonecookie

 

继续
session


执行了_request_ctx_stack.push(ctx)
也就是说_request_ctx_stack它把咱们的ctx对象push到了一个地方
咱们的ctx这个对象里面有request以及session等数据结构

 


这个初始化方法就是刚才python类的双下方法__setattr__
就是给Local类初始化了两个属性    __storage__ = {}            __ident_func__ = get_identapp

 

咱们继续看LocalStark中push方法作了什么
ide


如今回去看wsgi_app里的ctx.push(),到这里,它就走完了,接下来就要走视图
那到这里咱们能够经过什么样的方法在咱们视图中拿到这个request对象呢
request在ctx对象里能经过ctx.request获得,那咱们怎么获得ctx呢
ctx被LocalStack对象放入到Local中了函数

from flask import Flask
from flask import globals

app = Flask(__name__)


@app.route("/")
def index():
    ctx = globals._request_ctx_stack.top
    print(ctx.request.method)
    return "index"



if __name__ == '__main__':
    app.run()
获取ctx

 

3、Flask上下文管理(续)

这个request:
  from flask.globals import _request_ctx_stack
  ctx = _request_ctx_stack.top
  request = ctx.requestpost


和这个request:
  from flask import request


两个request有什么区别?


其实咱们导入的request跟咱们上面拿到的request是同样的。

下面看看怎么直接拿request

reqeust是LocalProxy这个类的实例化对象,参数是一个偏函数,
那当咱们调用request.method 等方法的时候走的是LocalProxy这个类的__getattr__方法

这里的_get_current_object()至关于咱们偏函数的执行

 

所以,直接导入的request也是经过LocalStack方法去Local中取ctx对象
而后经过getattr 找到ctx.request,
也就是说这个LocalProxy就是一个帮助咱们取值的代理,让咱们的取值变的更加简单
这个代理经过偏函数来绑定参数,
ctx中封装了request,以及session,只不过到这里咱们的session依然是空的。

 

4、session的实现原理

 _request_ctx_stack.push(self)走完后,会继续走这个

也就是说,请求进来把ctx放入Local中后,从前端解密了cookie,而后把解密数据好的数据给了self.session
继续走

那么session的实现机制:
  1. 请求进来获取cookie的值
  2. 解密cookie转换成字典(没有cookie就是空字典)赋值给ctx.session
  3. 当请求走的时候把session的数据加密
  4. 设置cookie

 

5、应用上下文管理

 应用上下文和请求上下文的原理和源码是同样的

也就是说,咱们请求上下文和应用上下文,分别创建了两个Local对象
两个Local对象数据结构都是同样的,那么请求上下文和应用上下文为何要分开存放呢
由于咱们写离线脚本的时候须要用到!

 

小结:
也就是说能够导入请求上下文的request, session和应用上下文的g, current_app
from flask import Flask, request, session, g, current_app

 

6、全局对象g

咱们说应用上下文里封装了g对象,那么这个g对象是什么呢
1. Flask中g的生命周期?
  咱们讲这么多上下文管理,咱们知道请求进来会为每一个请求在Local中创建一个独立空间
  也就是在应用上下文的Local对象中创建了一个g对象,当请求走的时候就会删除
  因此g的生命周期是一次请求的进来到离开。

 

2. g和session有什么区别?
  session有cookie,下次请求进来的时候能带数据过来

 

3. g和全局对象有什么区别?
  全局变量,是在项目启动建立的,直到项目中止才会销毁
  不管多少请求进来均可以访问全局变量
  而咱们的g对象通常状况用于before_request中设置值,只为这一次请求创建全局变量

 

4. Demo

复制代码
from flask import Flask, request, session, g, current_app
from flask.globals import _request_ctx_stack


app = Flask(__name__)


@app.before_request
def auth():
    g.xxx = "小明"


@app.route("/")
def index():
    ctx = _request_ctx_stack.top
    print(ctx.request)
    print(ctx.request.method)
    print(current_app)
    # request.xxx的执行过程
    # 1. request --> LocalProxy(偏函数)
    # 2. request.xxx --> LocalProxy  __getattr__
    # 3. __getattr__  --> getattr(偏函数的执行,xxx )
    # 4. 偏函数-->  _request_ctx_stack.top.request

    print(g.xxx)
    return "INDEX"


if __name__ == '__main__':
    app.run()
复制代码

 

7、Flask上下文管理图解

相关文章
相关标签/搜索