我使用flask_login管理登陆用户session,为了给登陆用户写日志,决定使用signals.代码如下:
@user_logged_in.connect_via(app)
def log_info(sender, user, **kw):
print 'test in log info'
current_app.behavior_logger.info(u'[login]%s login' % user.name)
然而该代码只能在有app变量的python文件中生效,在blueprint中无效。
我尝试app = current_app
或者app = xx_blueprint
均无效。
请问flask api文档中说的singals sender 是指什么,如何在blueprint中接受signal呢
Flask 文档中的那些 signals,它们的发送都是当前 flask app,因此,当你连接到 request_started
一类的 flask 框架级内置信号时,flask app 会向 receiver 发送信号。
此时的 sender 就是 app
,就是那个 app = flask.Flask(__name__)
的 app 对象。 receiver,就是注册到信号接收者列表中的函数们。
注意:
对于内置信号,当你注册好了以后,app 启动了以后,flask 会在相应的场景下主动 send,而不需要你手动 send,比如
request_started
,当请求开始时它就会发。内置信号之外的,你得自己来控制何时 send。
sender 必须是你 receiver 函数指定的同一对象。
回头来看题主的问题。
你的 @user_logged_in.connect_via(app)
将 app 设置为了 sender。
你改成 app = current_app
或者 app = xx_blueprint
肯定都是无效的,因为一来前面那个 current_app
并没有 send 什么出去,二来后面的 xx_blueprint
又不是 connect_via(app)
处的 app
。
so,如何在 blueprint 里接收信号呢?
connect_via(app)
的第一个参数需要改为你的 blueprint 对象在这个 blueprint 对象的相关上下文中 send 消息
比如:
my_signals = signals.Namespace()
signal_for_bp = my_signals.signal("bp")
bp_shajiquan = Blueprint("bp_shajiquan", __name__, url_prefix="/bp")
# 当信号通过 bp_shajiquan 连接时,也就是当 sender 为 bp_shajiquan 时
@signal_for_bp.connect_via(bp_shajiquan)
def log_bp_shajiquan(sender, *args, **kwargs):
print("信号 sender 及内容:", sender, kwargs)
assert(sender.name == "bp_shajiquan")
# bp_shajiquan 这个 blueprint 的每个请求前,都运行 before_every_request_in_bp 函数
@bp_shajiquan.before_request
def before_every_request_in_bp():
# 向信号发送消息,赞美良辰,每个请求,都会赞美……
signal_for_bp.send(bp_shajiquan, msg="你只需要记住,我叫叶良辰。每次请求,你都要记住!", name="良辰粉丝")
# 写个 view
@bp_shajiquan.route('/<string:username>')
def bp_shajiquan_user_profile(username):
signal_for_bp.send(bp_shajiquan, name="叶良辰", msg="你若是感觉有实力跟我玩,良辰不介意奉陪到底....")
# 这条就发不过去, 因为 sender 不匹配
signal_for_bp.send(app, name="良辰黑", msg="这条就发不过去....")
return "良辰找你很久了,亲爱的: " + username