我在收到post_save
信号时会对模型的对象执行一些持久性操作,其中包括对save()
的调用。显然,save()
调用再次发送post_save
信号,并且我正在信号递归中着陆。
有没有办法阻止Django在特定post_save
电话上发送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
模型)中触发。
答案 0 :(得分:4)
我通过调用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)
。
答案 1 :(得分:1)
首先:如果以不进行多线程处理的方式部署django程序(可以进行多处理!),可以随意断开信号,并且不会丢失任何其他线程的信号。
如果这不是一个选项,你也可以使用一些global thread-local state,它将包含信号被抑制的模型的原型键(和可能的类型)。