flask- 偏函数、请求上下文、信号、flask-session保存redis中

时间:2019-11-14
本文章向大家介绍flask- 偏函数、请求上下文、信号、flask-session保存redis中,主要包括flask- 偏函数、请求上下文、信号、flask-session保存redis中使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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在其中添加数据时,自动触发
Flask中内置信号在·signals.py中定义

  与信号绑定: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()
View Code

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()
View Code

调用from flask_session import Session

看Session源码,可以了解1、拼接session前缀,2、数据库指定等都可以自定义

原文地址:https://www.cnblogs.com/xiaowangba9494/p/11862745.html