如何创建单个装饰器统一处理多个mongoengine signal
实现方案
完全可以通过同一个装饰器同时覆盖新增、更新、删除三类事件的处理,不需要为不同事件单独定义不同命名的处理函数。
原有代码的限制来自装饰器设计:初始版本的handler仅支持传入单个信号事件,重复用同名函数绑定新事件会直接覆盖之前的绑定关系,因此只能处理单类事件。只需要调整装饰器逻辑,支持批量传入多个信号、在apply阶段统一绑定到同一个处理函数即可。
改造后代码
from mongoengine import signals, Document, StringField import sys # 改造装饰器,支持同时传入多个待绑定的信号事件 def handler(*events): def decorator(fn): def apply(cls): # 遍历所有传入的信号,全部绑定到当前处理函数 for event in events: event.connect(fn, sender=cls) return cls fn.apply = apply return fn return decorator # 一次绑定三类需要监听的信号: # post_save 覆盖单文档新增、单文档save更新场景 # post_delete 覆盖单文档删除场景 # post_bulk_update 覆盖QuerySet级批量更新场景 @handler(signals.post_save, signals.post_delete, signals.post_bulk_update) def event_handler(sender, document=None, **kwargs): # 识别当前触发的事件类型 current_signal = sys._getframe().f_locals.get('signal') event_type = "" extra_info = {} if current_signal == signals.post_save: event_type = "insert" if kwargs.get("created") else "update" elif current_signal == signals.post_delete: event_type = "delete" elif current_signal == signals.post_bulk_update: event_type = "bulk_update" # 批量操作无单个document对象,从kwargs提取操作信息 extra_info["filter"] = kwargs.get("query") extra_info["update_content"] = kwargs.get("update") # 统一编写审计逻辑 print(f"捕获Mongo操作事件:类型={event_type}, 操作对象={document or '批量操作'}, 额外信息={extra_info}") # 仅需一次装饰,即可让该文档类的所有三类操作都被监听 @event_handler.apply class SampleObject(Document): field1 = StringField() field2 = StringField() field3 = StringField() field4 = StringField()
注意事项
post_save信号触发时,可通过入参kwargs["created"]的布尔值直接区分操作是新增(值为True)还是单文档更新(值为False),不需要单独绑定更新信号- 如果需要覆盖QuerySet级别的批量删除场景,额外在
handler中传入signals.post_bulk_delete即可,该类批量操作同样不会传入单个document参数,操作信息需要从kwargs中提取 - 如果业务场景中不存在批量update、批量delete的直接QuerySet操作,仅绑定
post_save和post_delete两个信号就能覆盖所有新增、更新、删除场景
内容的提问来源于stack exchange,提问作者Hitesh Ghuge
相关产品推荐
相关产品推荐

