文章目录
- 信号与请求拓展的区别
- 使用信号触发和直接调用的区别
- 信号源码的说明
- 内置信号说明
- 自定义信号
信号 ---- 在满足某种情况下会触发某个函数的执行
信号与请求拓展的区别
信号可以触发一个或者多个绑定函数的执行,同时可以有返回值,而请求拓展的返回值是被严格限制的
信号的绑定程序的执行是按照绑定是的先后顺序执行的
使用信号触发和直接调用的区别
信号触发绑定函数的执行是在他自己的调用栈进行,而直接调用是在 flask 的请求上下文和全局上下文中进行的;这就意味着信号触发执行的时候是访问不到请求上下文和
g对象
的所以必要时,可以使用 flask 提供的请求上下文管理工具。
信号源码的说明
其实,从源码中可以看出,
Namespace
这个类会先尝试从blinker
模块中导入’如果导不到,就会使用下面自己写的
Namespace
;文件中间说明了
_signals = Namespace()
,所以使用这两个中的哪一个都行;使用
_signals
有一个单例模式的效果,所以尽量使用这个,保证一个项目中就一个总的信号触发机制文件最下方初始化了很多内置信号
import typing as ttry:from blinker import Namespacesignals_available = True
except ImportError:signals_available = Falseclass Namespace: # type: ignoredef signal(self, name: str, doc: t.Optional[str] = None) -> "_FakeSignal":return _FakeSignal(name, doc)class _FakeSignal:"""If blinker is unavailable, create a fake class with the sameinterface that allows sending of signals but will fail with anerror on anything else. Instead of doing anything on send, itwill just ignore the arguments and do nothing instead."""def __init__(self, name: str, doc: t.Optional[str] = None) -> None:self.name = nameself.__doc__ = docdef send(self, *args: t.Any, **kwargs: t.Any) -> t.Any:passdef _fail(self, *args: t.Any, **kwargs: t.Any) -> t.Any:raise RuntimeError("Signalling support is unavailable because the blinker"" library is not installed.") from Noneconnect = connect_via = connected_to = temporarily_connected_to = _faildisconnect = _failhas_receivers_for = receivers_for = _faildel _fail# The namespace for code signals. If you are not Flask code, do
# not put signals in here. Create your own namespace instead.
_signals = Namespace()# Core signals. For usage examples grep the source code or consult
# the API documentation in docs/api.rst as well as docs/signals.rst
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")
内置信号说明
内置信号会自动触发
request_started = _signals.signal('request-started') # 请求到来前执行
request_finished = _signals.signal('request-finished') # 请求结束后执行before_render_template = _signals.signal('before-render-template') # 模板渲染前执行
template_rendered = _signals.signal('template-rendered') # 模板渲染后执行got_request_exception = _signals.signal('got-request-exception') # 请求执行出现异常时执行request_tearing_down = _signals.signal('request-tearing-down') # 请求执行完毕后自动执行(无论成功与否)
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 应用上下文执行完毕后自动执行(无论成功与否)appcontext_pushed = _signals.signal('appcontext-pushed') # 应用上下文push时执行
appcontext_popped = _signals.signal('appcontext-popped') # 应用上下文pop时执行
message_flashed = _signals.signal('message-flashed') # 调用flash在其中添加数据时,自动触发
内置信号的使用
使用步骤:
第一步:写个函数–必须接受一些参数
第二步:跟信号绑定
第三步:触发信号
from flask import Flask, render_template
from flask import signalsapp = Flask(__name__)# 内置信号使用步骤
# 第一步:写个函数
def render_before(*args,**kwargs):print(args)print(kwargs)print('模板要渲染了')# 第二步:跟信号绑定
signals.before_render_template.connect(render_before)# 第三步:触发信号 (内置信号,会自动触发)@app.route('/')
def index():print('index 执行了')return render_template('index.html', name='刘亦菲')if __name__ == '__main__':app.run()
自定义信号
不会自动触发,只能手动触发,通过send方法
第一步:定义信号
第二步:写个函数
第三步:跟信号绑定
第四步:触发信号—指定触发时给绑定函数传递的参数
from flask import Flask, render_template,request
from flask import signals
from flask.signals import _signalsapp = Flask(__name__)# 第一步:定义信号
xxx = _signals.signal('xxx')# 第二步:写个函数
def add(*args, **kwargs):print(args)print(kwargs)print('add执行了')# 第三步:跟信号绑定
xxx.connect(add)#第四步:触发信号
@app.route('/')
def index():xxx.send(request=request)print('index 执行了')return render_template('index.html', name='刘亦菲')if __name__ == '__main__':app.run()