zoukankan      html  css  js  c++  java
  • 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、数据库指定等都可以自定义

  • 相关阅读:
    正在找工作/打算找工作的看过来!
    xx星空面试题
    买的书不少,看的书不多,这是病
    公司那么多 我想去面面
    Android设备直接运行java项目?还杀不死?
    node-sass安装失败 解决办法(linux和window)
    Vue + element控制鼠标右键菜单
    Vue.js中Promise、异步、同步、定时器
    选择器&伪类选择器
    根据城市名称获取对应的省份名称
  • 原文地址:https://www.cnblogs.com/xiaowangba9494/p/11862745.html
Copyright © 2011-2022 走看看