阻止特定save()调用的信号发送
我在接收到一个 post_save
信号时,正在对模型对象进行一些持久化操作,这里面包括调用 save()
。显然,调用 save()
又会发送一个 post_save
信号,这样就导致了信号的递归调用。
有没有办法让 Django 在特定的 save()
调用时不发送 post_save
信号?或者我能否在我的信号回调中检测到这个调用是否是“循环”调用?
这个方法不行
我尝试通过给模型对象添加一个属性来修改它,但似乎 django.db.models.base.Model.save_base
会传递一个“清理过的”对象给信号回调,这个对象已经不再包含那个属性了:
def callback(sender, **kwargs):
instance = kwargs['instance']
if not hasattr(instance, 'no_signal'):
# (...) Perform actions
instance.no_signal = True
instance.save()
post_save.connect(callback, dispatch_uid='post_save_callback')
背景
整个情况比单纯接收信号、修改对象和持久化要复杂一些。实际上,我有两个相同的 Django 实例(在不同的服务器上),它们通过 ØMQ 交换创建或修改的对象,并在自己的数据库中持久化这些对象。我不想使用任何形式的数据库同步,因为这个应用需要容易部署,甚至应该能在 sqlite 上运行。
由于这应该适用于所有模型,无论它们是通过视图还是管理应用创建或修改的,我更希望找到一种方法来使用 post_save
信号,而不是引入一个自己的信号,这个信号需要在项目的多个地方触发(包括 User
模型)。
2 个回答
首先,如果你在部署你的Django程序时不使用多线程(你可以使用多进程!),那么你可以随意断开信号,这样就不会丢失其他线程的信号。
如果这不是一个选项,你还可以使用一些全局线程本地状态,这个状态会包含被抑制信号的模型的主键(可能还有类型)。
我通过调用 save_base(raw=True)
来解决这个问题,而不是用 save()
,然后在信号处理器中检查 kwarg['raw']
。
def receive_signal(sender, **kwargs):
instance, raw = kwargs['instance'], kwargs['raw']
if not raw:
# Send the instance to the other Django node
实际上,我使用 django.core.serializers.deserialize
来反序列化我接收到的对象,然后对这些反序列化的对象执行 save()
,这会调用模型的 save_base(raw=True)
。