local
from threading import get_ident,Thread
使用thread local对象可以基于线程存储全局变量,但在web引用中出现两个问题:
1、有些应用使用的greenlet协程,无法保证数据隔离的问题,因为不同协程在同一个线程中;
2.、无法保证每个http请求使用的都是不同的线程,这样存储thread local的数据可能是之前残留的
所以werkzeug开发自己local对象,解决上述问题
即通过线程id(或协程id)来分别存储数据。
偏函数:
调用:import:from functools import partial
定义一个偏函数,调用偏函数,如果原函数传参数,永远函数的参数,缺值可用偏函数参数
def add(a, b=2): return a + b def add2(a=2, b=3): return a + b if __name__ == "__main__": mysum = partial(add, 10) print mysum() # 也可根据关键字预先设定的参数值 mysum2 = partial(add, b=3) print mysum2(1) # 如果没有关键字,按原有参数顺序补充 mysum3 = partial(add2, 1) print mysum3() # 结果 12 4 ———————————————— 版权声明:本文为CSDN博主「HQ_JSY」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/JSYhq/article/details/88633426
请求上下文
1 app.__call__ 2 wsgi_app(environ, start_response) 2.1 ctx = self.request_context(environ) 2.1.1 return RequestContext(self, environ) 这里的self是app,environ请求相关 2.1.2 return RequestContext(self, environ) 得到了RequestContext的对象,而且有request属性 2.2 2.1中的ctx就是RequestContext的对象 2.3 ctx.push()执行这个,就是RequestContext的对象的push方法 2.3.1 #执行这个,self-->ctx _request_ctx_stack.push(self) 2.3.1.1 我们发现_request_ctx_stack = LocalStack() 他的push方法的源码: def push(self, obj): rv = getattr(self._local, "stack", None) if rv is None: # self._local=>stack-->storage['线程id']['stack']=[ctx,] self._local.stack = rv = [] rv.append(obj) return rv 3在请求中获取request.form 3.1 request是LocalProxy的对象,当获取属性的时候会走__getattr__ def __getattr__(self, name): if name == "__members__": return dir(self._get_current_object()) #name-->form, #self._get_current_object()===>ctx.request,form #_get_current_object()---》self.__local() return getattr(self._get_current_object(), name) 3.1.1 self._get_current_object():源码:最终:partial(_lookup_req_object, "request") def _get_current_object(self): if not hasattr(self.__local, "__release_local__"): #local==>partial(_lookup_req_object, "request") #def __init__(self, local, name=None): # object.__setattr__(self, "_LocalProxy__local", local) #self.__local()===>local() return self.__local() try: return getattr(self.__local, self.__name__) except AttributeError: raise RuntimeError("no object bound to %s" % self.__name__) 4 partial(_lookup_req_object, "request")偏函数的源码 def _lookup_req_object(name): #name是request #ctx top = _request_ctx_stack.top if top is None: raise RuntimeError(_request_ctx_err_msg) #ctx-->request return getattr(top, name) 4.1中_request_ctx_stack.top @property def top(self): try: return self._local.stack[-1] except (AttributeError, IndexError): return None
g对象:
当前请求内设置便可以取值,必须先设置后取值,当前请求可以取无限次(其他请求取不到)
from flask import Flask, g, render_template, request from ulits import login_log app = Flask(__name__) @app.route('/') def hello_world(): return 'index' @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') else: username = request.form.get('username') password = request.form.get('password') if username == 'zhiliao' and password == '111111': g.username = username login_log() return '恭喜您!登录成功' else: return '登录名或密码错误!' if __name__ == '__main__': app.run(debug=True, host='127.0.0.1', port=8081)
from flask import g def login_log(): print('登录名为: {}'.format(g.username))
信号:
往信号中注册函数,无序调用,因为flask已经给我们设置了调用点
1 template_rendered = _signals.signal('template-rendered') # 模板渲染后执行 2 before_render_template = _signals.signal('before-render-template') # 模板渲染前执行 3 request_started = _signals.signal('request-started') # 请求到来前执行 4 request_finished = _signals.signal('request-finished') # 请求结束后执行 5 request_tearing_down = _signals.signal('request-tearing-down') # 请求执行完毕后自动执行(无论成功与否) 6 got_request_exception = _signals.signal('got-request-exception') # 请求执行出现异常时执行 7 appcontext_tearing_down = _signals.signal('appcontext-tearing-down') # 应用上下文执行完毕后自动执行(无论成功与否) 8 appcontext_pushed = _signals.signal('appcontext-pushed') # 应用上下文push时执行 9 appcontext_popped = _signals.signal('appcontext-popped') # 应用上下文pop时执行 10 message_flashed = _signals.signal('message-flashed') # 调用flash在其中添加数据时,自动触发
与信号绑定:signals.request_started.connect(func)
触发信号:signals.request_started.send()
自定义信号:
xxxxx = _signals.signal('xxxxx')
from flask import Flask from flask.signals import _signals app = Flask(import_name=__name__) # 自定义信号 xxxxx = _signals.signal('xxxxx') def func(sender,a): print(sender,a) print("我是自定义信号") # 自定义信号中注册函数 xxxxx.connect(func) @app.route("/x") def index(): # 触发信号 xxxxx.send("sb",a="1") return 'Index' if __name__ == '__main__': app.run()
flask-session保存到redis中
1、基础方法
安装pip3 install flask-session
from flask import Flask,session from flask_session import RedisSessionInterface import redis app = Flask(__name__) app.secret_key="ajksda" conn=redis.Redis(host='127.0.0.1',port=6379) #use_signer是否对key签名 app.session_interface=RedisSessionInterface(conn,key_prefix='jason',use_signer=True, permanent=False) @app.route('/') def hello_world(): session['sb']='jason' return 'Hello World!' @app.route("/index") def index(): print(session['sb']) return "ok" if __name__ == '__main__': app.run()
key_prefix='前缀':拼接session的前缀
use_signer=True:是否对key签名(即app.sercet_key不需要设置)
permanent=False:True关闭再开浏览器,值还在
2、常用方法
from flask import Flask,session import redis from flask_session import Session app = Flask(__name__) app.config['SESSION_TYPE'] = 'redis' app.config['SESSION_REDIS'] =redis.Redis(host='127.0.0.1',port='6379') app.config['SESSION_KEY_PREFIX']="jason" Session(app) @app.route('/') def hello_world(): session['sb']='jason' return 'Hello World!' @app.route("/index") def index(): print(session['sb']) return "ok" if __name__ == '__main__': app.run()
调用from flask_session import Session
看Session源码,可以了解1、拼接session前缀,2、数据库指定等都可以自定义