信号 ---- 在满足某种情况下会触发某个函数的执行
信号与请求拓展的区别
信号可以触发一个或者多个绑定函数的执行,同时可以有返回值,而请求拓展的返回值是被严格限制的
信号的绑定程序的执行是按照绑定是的先后顺序执行的
使用信号触发和直接调用的区别
信号触发绑定函数的执行是在他自己的调用栈进行,而直接调用是在 flask 的请求上下文和全局上下文中进行的;这就意味着信号触发执行的时候是访问不到请求上下文和
g对象
的所以必要时,可以使用 flask 提供的请求上下文管理工具。
信号源码的说明
其实,从源码中可以看出,
Namespace
这个类会先尝试从blinker
模块中导入’如果导不到,就会使用下面自己写的
Namespace
;文件中间说明了
_signals = Namespace()
,所以使用这两个中的哪一个都行;使用
_signals
有一个单例模式的效果,所以尽量使用这个,保证一个项目中就一个总的信号触发机制文件最下方初始化了很多内置信号
import typing as t
try:
from blinker import Namespace
signals_available = True
except ImportError:
signals_available = False
class Namespace: # type: ignore
def 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 same
interface that allows sending of signals but will fail with an
error on anything else. Instead of doing anything on send, it
will just ignore the arguments and do nothing instead.
"""
def __init__(self, name: str, doc: t.Optional[str] = None) -> None:
self.name = name
self.__doc__ = doc
def send(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
pass
def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
raise RuntimeError(
"Signalling support is unavailable because the blinker"
" library is not installed."
) from None
connect = connect_via = connected_to = temporarily_connected_to = _fail
disconnect = _fail
has_receivers_for = receivers_for = _fail
del _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 signals
app = 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 _signals
app = 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()