阻止特定save()调用的信号发送

6 投票
2 回答
2385 浏览
提问于 2025-04-18 07:08

我在接收到一个 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 个回答

1

首先,如果你在部署你的Django程序时不使用多线程(你可以使用多进程!),那么你可以随意断开信号,这样就不会丢失其他线程的信号。

如果这不是一个选项,你还可以使用一些全局线程本地状态,这个状态会包含被抑制信号的模型的主键(可能还有类型)。

6

我通过调用 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)

另请参见: https://stackoverflow.com/a/22560210/145013

撰写回答