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 @   thep0st  阅读(75)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示