Flask 进阶session和上下文管理解析
session的源码流程
将session放置在redis中
安装
pip install flask-session
使用
import redis
from flask import Flask,request,session
from flask.sessions import SecureCookieSessionInterface
from flask_session import Session app = Flask(__name__)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.Redis(host='140.143.227.206',port=6379,password='')
Session(app) @app.route('/login')
def login():
session['user'] = 'alex'
return 'asdfasfd' @app.route('/home')
def index():
print(session.get('user')) return '...' if __name__ == '__main__':
app.run()
上下文管理基础
上下文管理之基础threading.local
1.threading.local
- 实例化一个local对象
- obj.xxxx=i会触发__setattr__ 设置值
- obj.xxxx的会触发__getattr__取值
- local能为每一个线程开辟一个新的空间,让每个线程的资源相互不干扰
import threading,time
from threading import local
obj=local()
def task(i):
obj.xxxxx = i
time.sleep(2)
print(obj.xxxxx,i) for i in range(0,10):
t=threading.Thread(target=task,args=(i,))
t.start()
2.用字典替换local
import threading,time
from threading import local obj=local()
DIC={}
def task(i):
ident = threading.get_ident()
if ident in DIC:
DIC[ident]['xxxx']=i
else:
DIC[ident]={'xxxx':i}
time.sleep(2)
print(DIC[ident]['xxxx'],i,ident)
for i in range(0,10):
t=threading.Thread(target=task,args=(i,))
t.start()
ident = threading.get_ident() 获取线程的唯一标识
- 将所有的数据根据线程唯一标示为key存放到字典里,那么该方法也可以避免线程资源冲突...因为DIC是一个全部变量字典
3. 重写local支持协程
import threading,time,greenlet
try:
get_ident=greenlet.getcurrent
except Exception as e:
get_ident=threading.get_ident
class Local(object):
DIC={}
def __getattr__(self, item):
ident = get_ident()
print(ident)
if ident in self.DIC:
return self.DIC[ident].get(item)
return None
def __setattr__(self, key, value):
ident= get_ident()
if ident in self.DIC:
self.DIC[ident][key]=value
else:
self.DIC[ident]={key:value}
obj=Local()
def task(i):
obj.ha=i
time.sleep(2)
print(obj.ha)
for i in range(0,10):
t= threading.Thread(target=task,args=(i,))
t.start()
上下文管进阶理解
1.偏函数
# by luffycity.com
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)
2.执行父类方法
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()
# print(Foo.__mro__)
3.object.__setattr__
class Foo(object):
def __init__(self):
# self.storage = {}
# 在父类的setattr设置storage为空列表
object.__setattr__(self,'storage',{})
def __getattr__(self, item):
print item def __setattr__(self, key, value):
print(key,value,self.storage) obj = Foo()
obj.xx = 123
- obj=Foo() 实例化对象会执行,__new__......再执行__init__方法加上object.__setattr__会执行object类的方法设置值
- obj.xx=123设置值会执行该类的__setattr__
4.Flask Local源码
- local是用来给每个线程或者协程开辟一个空间
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):
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)
5.LocalStack源码
- localstack 维护local的列表,维护成一个栈
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
源码入口
app.__call__
app.wsgi_app
上下文管理request简易流程图
上下文管理request,session流程
- -请求到来之后会触发__call__方法,由__call__方法再次调用wsgi__app方法
- -在wsgi_app方法中:
- -首先将请求相关+空session封装到一个RequestContext对象中即:ctx
- -将ctx交给LocalStack对象,再由LocalStack将ctx添加到local中,Local结构:
- __storage__={
- 线/协程的唯一标识:{stack:[ctx,]}
- -根据请求中的cookie中提取铭文sessionid对应的值,对cookie进行加密+反序列化
- ->视图函数
- -把session中的数据再次加密序列化写入到cookie中.
- -将ctx删除
- -结果返回给用户浏览器
- -断开socket连接.
#LocalStack是全局的 单例模式
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
上下文管理最终流程图
Flask 进阶session和上下文管理解析的更多相关文章
- Flask - 请求处理流程和上下文源码分析
目录 Flask - 请求处理流程和上下文 WSGI Flask的上下文对象及源码解析 0. 请求入口 1.请求上下文对象的创建 2. 将请求上下文和应用上下文入栈 3.根据请求的URl执行响应的视图 ...
- with和上下文管理器
with和上下文管理器 如果你有时间阅读源码的习惯,可能会看到一些优秀的代码会出现带有with关键字的语句. 对于系统资源如文件,数据库连接,socket而言,应用程序打开这些资源并执行完业务逻辑之后 ...
- flask 状态保持session和上下文session的区别
问题场景: 在falsk项目中导入了两个session: 首先,配置文件config.py文件中 有个 flask_session扩展导入了Session ( from flask_sessi ...
- 文件操作-with和上下文管理器
代码: # -*- coding:utf-8 -*- # 普通版 如果写入的过程中出错 则不会释放资源 def m1(): f = open("test.txt","w& ...
- Python with语句和上下文管理器
open("FishC.txt","w")#此处需注意如果被打开的文件中,已有内容,那么用w的方式打开,则会导致原文件内容被截断,也就是相当于被清空了,然后重新 ...
- flask 中 session的源码解析
1.首先请求上下文和应用上下文中已经知道session是一个LocalProxy()对象 2.然后需要了解整个请求流程, 3.客户端的请求进来时,会调用app.wsgi_app(),于此此时,会生成一 ...
- python with和上下文管理工具
对于系统资源如文件.数据库连接.socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源. 比如 Python 程序打开一个文件,往文件中写内容,写完之后, ...
- jsp中的session和上下文
Session的典型应用: 防止用户非法登录到某个页面. 网上商城的购物车 保存用户登录信息 注:多个请求要用的东西放在session中,多个会话之间要用的东西放在上下文中. 如何创建session? ...
- django-10-中间件和上下文管理器
<<<中间件的引入>>> 用户<->中间件<->url->视图 在app目录里面 middleware.py (1)中间件就是一个 ...
随机推荐
- caffe卷积层代码阅读笔记
卷积的实现思想: 通过im2col将image转为一个matrix,将卷积操作转为矩阵乘法运算 通过调用GEMM完毕运算操作 以下两个图是我在知乎中发现的,"盗"用一下,确实非常好 ...
- Intellij output 中文乱码
使用intellij有一段时间了,intellij output中文乱码,每次使用这两点解决,就可以解决乱码问题. 1.修改启动参数 修改安装Intellij目录下的C:\Program Files ...
- redis有序集合的一个应用
一.需求 记录用户uid和上次操作时间;并清除5分钟以前的数据.用redis的一个key实现.本打算用hash,但hash类型在过期5分钟以前的数据时颇为麻烦. 二.代码实现 class LastLo ...
- Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.
1.Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'. 原因解析: gradle ...
- 最简单的基于FFmpeg的移动端样例附件:Android 自带播放器
===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:A ...
- SDUT 2766-小明传奇2(母函数)
小明传奇2 nid=24#time" title="C.C++.go.haskell.lua.pascal Time Limit1000ms Memory Limit 65536K ...
- java清除所有微博短链接 Java问题通用解决代码
java实现微博短链接清除,利用正则,目前只支持微博短链接格式为"http://域名/字母或数字8位以内"的链接格式,现在基本通用 如果链接有多个,返回结果中会有多出的空格,请注意 ...
- WCF实现上传图片功能
初次学习实现WCF winform程序的通信,主要功能是实现图片的传输. 下面是实现步骤: 第一步: 首先建立一个类库项目TransferPicLib,导入wcf需要的引用System.Service ...
- Delphi中定义了四种布尔类型:Boolean,ByteBool,WordBool和LongBool。后面三种布尔类型是为了与其他语言兼容而引入的
bool是LongBool类型. Delphi中定义了四种布尔类型:Boolean,ByteBool,WordBool和LongBool.后面三种布尔类型是为了与其他语言兼容而引入的,一般情况下建议使 ...
- Python script to create Screen from all Items/Graphs of a host
#!/usr/bin/env python import urllib2 import json import argparse def authenticate(url, username, pas ...