9.flask信号(能自定义的扩展点)

1.什么是信号?

一般是框架内的高级用法
是一个钩子,当执行到。。。的时候,就自动执行。。。方法或者函数,让我们可以进行一些自定义的操作

2.flask中有关的信号(扩展点)

根据请求的先后的顺序--视图函数未执行之前

中间件

app.wsgi_app = MyMiddleware(app.wsgi_app)
将函数注册到appcontext_pushed信号里面,当将app_ctx对象加入到栈之后,会触发该信号
appcontext_pushed.send(self.app),也就是执行完这句代码之后会触发f1函数
在AppConttext类里面
from flask import Flask,render_template

app = Flask(__name__)


@app.route('/index')
def index():
    return render_template('index.html')


@app.route('/order')
def order():
    return render_template('order.html')


class MyMiddleware(object):
    def __init__(self,old_app):
        self.wsgi_app = old_app.wsgi_app

    def __call__(self, *args, **kwargs):
        print('123')
        result = self.wsgi_app(*args, **kwargs)
        print('456')
        return result

app.wsgi_app = MyMiddleware(app)

if __name__ == '__main__':
    app.run()
View Code

信号.appcontext_pushed.send

是由app_ctx.push()来触发的
当app_ctx被push到local中栈之后,会触发appcontext_pushed信号,之前注册在这个信号中的方法,就会被执行。
from flask import Flask,render_template
from flask import signals

app = Flask(__name__)

@signals.appcontext_pushed.connect
def f1(arg):
    print('appcontext_pushed信号f1被触发',arg)

@signals.appcontext_pushed.connect
def f2(arg):
    print('appcontext_pushed信号f2被触发',arg)

@app.route('/index')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
    # app.__call__
View Code

装饰器.before_first_request

由self.try_trigger_before_first_request_functions()来触发的
from flask import Flask,render_template

app = Flask(__name__)

@app.before_first_request
def f2():
    print('before_first_requestf2被触发')

@app.route('/index')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

信号.request_started

由 request_started.send(self)来触发
from flask import Flask,render_template
from flask import signals
app = Flask(__name__)

@signals.request_started.connect
def f3(arg):
    print('request_started信号被触发',arg)

@app.route('/index')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

self.preprocess_request() 里面有两个扩展点(url_value_preprocessor和before_request)

装饰器.url_value_preprocessor

执行url_value_preprocessor,由funcs = self.url_value_preprocessors.get(None, ())来触发的
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)


@app.url_value_preprocessor
def f5(endpoint,args):
    print('f5')

@app.route('/index/')
def index():
    print('index')
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

装饰器.before_request

执行before_request,由funcs = self.before_request_funcs.get(None, ())来触发的
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)

@app.before_request
def f6():
    g.xx = 123
    print('f6')

@app.route('/index/')
def index():
    print('index')
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

根据请求的先后的顺序--视图函数执行时

信号.before_render_template和信号template_rendered

return render_template('index.html')里面也有可扩展的信号,是在视图函数最后一步,也就是给用户返回信息的时候
render_template源码
def _render(template, context, app):
"""Renders the template and fires the signal"""
# 模板渲染之前
before_render_template.send(app, template=template, context=context)
# 模板渲染
rv = template.render(context)
# 模板渲染之后
template_rendered.send(app, template=template, context=context)
return rv
# template是模板路经,context是返回时传递的参数
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)

@signals.before_render_template.connect
def f7(app, template, context):
    print('f7')

@signals.template_rendered.connect
def f8(app, template, context):
    print('f8')

@app.route('/index/')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

finalize_request里面有两个扩展点(after_request和request_finished)

装饰器.after_request

执行after_request,由response = self.process_response(response)来触发的    
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)

@app.after_request
def f9(response):
    print('f9')
    return response

@app.route('/index/')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

信号.request_finished

执行request_finished,由request_finished.send(self, response=response)来触发的
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)

@signals.request_finished.connect
def f10(app,response):
    print('f10')

@app.route('/index/')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

根据请求的先后的顺序--视图函数执行之后,异常处理阶段
信号.got_request_exception

执行got_request_exception,由flask中的源码部分出现异常才会捕获,因为在源码部分有的没有做异常处理,而在试图阶段都做了异常处理
比如在request_first阶段就没有异常处理(源码中没有异常处理的都可以捕获的到)

注意:
  在flask源码出现异常的时候,after_request和request_finished的扩展点可会执行一遍

from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)

@app.before_first_request
def test():
    int('asdf')

@signals.got_request_exception.connect
def f11(app,exception):
    print('f11')

@app.route('/index/')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

根据请求的先后的顺序--视图函数执行之后,垃圾回收阶段
ctx.auto_pop(error)垃圾回收阶段有两个扩展点(teardown_request和request_tearing_down)
装饰器.teardown_request

执行teardown_request,由ctx.auto_pop(error)触发,里面的self.pop(exc)的 self.app.do_teardown_request(exc)函数。
是在请求结束之后无论成功与否,都想执行的功能,是在auto_pop之前执行.

 在self.app.do_teardown_request(exc)阶段也会触发一个信号
 信号request_tearing_down.send(self, exc=exc) 

from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)

@app.teardown_request
def f12(exc):
    print('f12')

@app.route('/index/')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

信号.request_tearing_down

from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)

@signals.request_tearing_down.connect
def f13(app,exc):
    print('f13')

@app.route('/index/')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

信号.appcontext_popped.send

appcontext对象删除之后做的事情
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__)

@signals.appcontext_popped.connect
def f14(app):
    print('f14')

@app.route('/index/')
def index():
    return render_template('index.html')

@app.route('/order')
def order():
    print('order')
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code

信号.message_flashed

基于session实现的用于保存数据的集合,特点是:存放的值,只能使用一次,然后就删除。在里面赋值的时候会触发message_flashed信号
        
from flask import Flask,render_template,flash,get_flashed_messages,session
from flask import signals
app = Flask(__name__)
app.secret_key = 'iuknsoiuwknlskjdf'

@app.route('/index/')
def index():
    # flash('123')
    session['k1'] = 123
    return render_template('index.html')

@app.route('/order')
def order():
    # messages = get_flashed_messages()
    # print(messages)
    val = session['k1']
    del session['k1']
    print(val)
    return render_template('order.html')

if __name__ == '__main__':
    app.run()
View Code 

总结:

总结:
        关于flask内部共有14+个扩展点用于我们对flask框架内部进行定制,其中有:9个是信号,其他的是5个装饰器
        template_rendered = _signals.signal("template-rendered")
        before_render_template = _signals.signal("before-render-template")
        request_started = _signals.signal("request-started")
        request_finished = _signals.signal("request-finished")
        request_tearing_down = _signals.signal("request-tearing-down")
        got_request_exception = _signals.signal("got-request-exception")
        appcontext_tearing_down = _signals.signal("appcontext-tearing-down")
        appcontext_pushed = _signals.signal("appcontext-pushed")
        appcontext_popped = _signals.signal("appcontext-popped")
        message_flashed = _signals.signal("message-flashed")  # 基于session实现的用于保存数据的集合,特点是:存放的值,只能使用一次,然后就删除。在里面赋值的时候会触发message_flashed信号
from flask import signals里面可以查看全部的信号和扩展点

 

 

 

 

 

 

 

 

 

 

 

pass

 

posted @ 2019-11-29 23:50  thep0st  阅读(85)  评论(0)    收藏  举报