【Flask】上下文管理

Flask 上下文管理基本流程

当浏览器发送请求到服务器时,在flask内部源码如下

# 第1步,封装session,再次封装请求数据
# ctx = RequestContext(self, environ) # self是app对象,environ请求是相关的原始数据
# ctx.request = Request(environ)
# ctx.session = None

# 第2步,将包含了request/session的ctx对象放到"空调"
       {
               1232:{ctx:ctx对象}
               1231:{ctx:ctx对象}
               1211:{ctx:ctx对象}
               1111:{ctx:ctx对象}
               1261:{ctx:ctx对象}
       }

#第3步,接着执行视图函数

#第4步,请求结束,根据当前线程的唯一标记,将“空调”上的数据移除

有关上下文管理的预备知识

  1. 偏函数
import functools

def index(a1,a2):
    return a1 + a2

# 原来的调用方式
# ret = index(1,23)
# print(ret)

# 偏函数,帮助开发者自动传递参数
new_func = functools.partial(index,666)    #传入函数名,和预置另一个参数
ret = new_func(1)
print(ret)
  1. super关键字
"""
class Base(object):

    def func(self):
        print('Base.func')

class Foo(Base):

    def func(self):
        # 方式一:根据mro的顺序执行方法
        # super(Foo,self).func()
        # 方式二:主动执行Base类的方法
        # Base.func(self)

        print('Foo.func')


obj = Foo()
obj.func()
"""
####################################
class Base(object):

    def func(self):
        super(Base, self).func()
        print('Base.func')

class Bar(object):
    def func(self):
        print('Bar.func')

class Foo(Base,Bar):
    pass

# 示例一
obj = Foo()
obj.func()
print(Foo.__mro__)

# 示例二
# obj = Base()
# obj.func()
  1. 面向对象中特殊的方法
class Foo(object):
    def __init__(self):
        # self.storage = {}    #该句会调用__setattr__方法,但self.storage还没创建,会报错
        object.__setattr__(self,'storage',{})      #调用父类方法中的__setattr__方法

    def __setattr__(self, key, value):
        print(key,value,self.storage)   

obj = Foo()
obj.xx = 123     #调用Foo类 __setattr__方法
  1. 实现栈结构
class Stack(object):

    def __init__(self):
        self.data = []

    def push(self,val):
        self.data.append(val)

    def pop(self):
        return self.data.pop()

    def top(self):
        return self.data[-1]

_stack = Stack()

_stack.push('佳俊')
_stack.push('咸鱼')

print(_stack.pop())
print(_stack.pop())
  1. local类,开辟内存空间

"""
{
    1232:{k:v}
}


"""
try:
    from greenlet import getcurrent as get_ident
except:
    from threading import get_ident

"""
class Local(object):
    
    def __init__(self):
        object.__setattr__(self,'storage',{})
    
    def __setattr__(self, key, value):
        ident = get_ident()
        if ident not in self.storage:
            self.storage[ident] = {key:value}
        else:
            self.storage[ident][key] = value
            
    def __getattr__(self, item):
        ident = get_ident()
        if ident in self.storage:
            return self.storage[ident].get(item)
"""

#flask 源码部分也有local类
class Local(object):
    __slots__ = ('__storage__', '__ident_func__')

    def __init__(self):
        # __storage__ = {1231:{'stack':[]}}
        object.__setattr__(self, '__storage__', {})
        object.__setattr__(self, '__ident_func__', get_ident)

    def __getattr__(self, name):
        try:
            return self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name] = value
        except KeyError:
            storage[ident] = {name: value}

    def __delattr__(self, name):
        try:
            del self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)



obj = Local()
obj.stack = []
obj.stack.append('佳俊')
obj.stack.append('咸鱼')
print(obj.stack)
print(obj.stack.pop())
print(obj.stack)
  1. localstack类,帮助维护loacl对象中的列表,成栈结构
import functools
try:
    from greenlet import getcurrent as get_ident
except:
    from threading import get_ident

class Local(object):
    __slots__ = ('__storage__', '__ident_func__')

    def __init__(self):
        # __storage__ = {1231:{'stack':[]}}
        object.__setattr__(self, '__storage__', {})
        object.__setattr__(self, '__ident_func__', get_ident)

    def __getattr__(self, name):
        try:
            return self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        # name=stack
        # value=[]
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name] = value
        except KeyError:
            storage[ident] = {name: value}

    def __delattr__(self, name):
        try:
            del self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)


"""
__storage__ = {
    12312: {stack:[ctx(session/request) ,]}
}

"""

# obj = Local()
# obj.stack = []
# obj.stack.append('佳俊')
# obj.stack.append('咸鱼')
# print(obj.stack)
# print(obj.stack.pop())
# print(obj.stack)


class LocalStack(object):
    def __init__(self):
        self._local = Local()

    def push(self,value):
        rv = getattr(self._local, 'stack', None) # self._local.stack =>local.getattr
        if rv is None:
            self._local.stack = rv = [] #  self._local.stack =>local.setattr
        rv.append(value) # self._local.stack.append(666)
        return rv


    def pop(self):
        """Removes the topmost item from the stack, will return the
        old value or `None` if the stack was already empty.
        """
        stack = getattr(self._local, 'stack', None)
        if stack is None:
            return None
        elif len(stack) == 1:
            return stack[-1]
        else:
            return stack.pop()

    def top(self):
        try:
            return self._local.stack[-1]
        except (AttributeError, IndexError):
            return None

class RequestContext(object):
    def __init__(self):
        self.request = "xx"
        self.session = 'oo'

_request_ctx_stack = LocalStack()
_request_ctx_stack.push(RequestContext())


def _lookup_req_object(arg):

    ctx = _request_ctx_stack.top()
    return getattr(ctx,arg) # ctx.request / ctx.session

request = functools.partial(_lookup_req_object,'request')
session = functools.partial(_lookup_req_object,'session')


print(request())
print(session())
  1. slots用法,限制对象访问变量
class Foo(object):
    __slots__ = ('name',)    #限制类的对象,只能外部调用name变量
    def __init__(self):
        self.name = 'alex'
        # self.age = 18


obj = Foo()
print(obj.name)
# print(obj.age)     #会报错

flask 上下文管理流程

先看一个简单的flask程序

from flask import Flask

app = Flask(__name__)

@app.route('/index')
def index():
    print("index")
    return '...'
  
  if __name__ == "__main__":
     app.run()

(1)上下文管理:request
执行app.run()后,会执行app.__call__方法,此时又会调用app.wsgi_app,大致调用流程如下

#第一步   
wsgi

#第二步
ctx = ReuqestContext(session,request)   #将请求数据和session封装在ctx对象中
ctx.push()       #将ctx对象加入到__storage__字典中

#第三步
LocalStack 把ctx对象添加到local中

#第四步
Local里存放的数据为字典类型
__storage__={
     1321:{stack:[ctx,]}
}

在这里插入图片描述

(2)上下文管理:session

大致步骤与上下文管理request相同,只有获取session并给session赋值有区别

第一步:   
 wsgi
第二步:
ctx = ReuqestContext(session=None,request)
ctx.push()
第三步:
LocalStack,把ctx对象添加到local中
第四步:
Local,为字典中的元素开辟独立空间
         __storage__={
            1321:{stack:[ctx,]}
         }
第五步:
获取ctx中的session,给session赋值(从cookie中读取数据) =>通过调用 open_session给session赋值 

上下文管理总结

  • 请求到来之后wsgi会触发__call__方法,由__call__方法再次调用wsgi_app方法
  • 在wsgi_app方法中:
    • 首先将 请求相关数据+空session 封装到一个RequestContext对象中,即:ctx

    • ctx交给LocalStack对象,再由LocalStackctx添加到Local中,Local结构如下:
      storage = {
      1231:{stack:[ctx,] }
      }

    • 根据请求中的cookie中提取名称为sessionid对应的值,对cookie进行解密+反序列化,再次赋值给ctx中的session

    • 执行视图函数

    • session中的数据再次写入到cookie中。

    • ctx删除

  • 结果返回给用户浏览器
  • 断开socket连接
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bug 挖掘机

支持洋子

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值