我遇到的情况是保存我的某个模型MyModel
我想检查一个字段,并在具有相同some_key.
代码工作正常,但它以递归方式调用信号。结果我浪费了CPU / DB / API调用。我基本上想在.save().
任何建议期间绕过信号?
class MyModel(models.Model):
#bah
some_field = #
some_key = #
#in package code __init__.py
@receiver(models_.post_save_for, sender=MyModel)
def my_model_post_processing(sender, **kwargs):
# do some unrelated logic...
logic = 'fun! '
#if something has changed... update any other field with the same id
cascade_update = MyModel.exclude(id=sender.id).filter(some_key=sender.some_key)
for c in cascade_update:
c.some_field = sender.some_field
c.save()
答案 0 :(得分:4)
在致电save
之前断开信号,然后重新连接:
post_save.disconnect(my_receiver_function, sender=MyModel)
instance.save()
post_save.connect(my_receiver_function, sender=MyModel)
答案 1 :(得分:3)
解决方案可能是使用update()方法来绕过信号:
cascade_update = MyModel.exclude(
id=sender.id).filter(
some_key=sender.some_key).update(
some_field = sender.some_field )
答案 2 :(得分:1)
断开信号不是 DRY 和一致解决方案,例如使用update()而不是save()。
要绕过模型上的信号触发,一个简单的方法是在当前实例上设置一个属性,以防止即将发出的信号。
这可以使用一个简单的装饰器来完成,该装饰器检查给定实例是否具有'skip_signal'属性,如果是,则阻止调用该方法:
from functools import wraps
def skip_signal():
def _skip_signal(signal_func):
@wraps(signal_func)
def _decorator(sender, instance, **kwargs):
if hasattr(instance, 'skip_signal'):
return None
return signal_func(sender, instance, **kwargs)
return _decorator
return _skip_signal
根据你的例子,这给了我们:
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=MyModel)
@skip_signal()
def my_model_post_save(sender, instance, **kwargs):
instance.some_field = my_value
# Here we flag the instance with 'skip_signal'
# and my_model_post_save won't be called again
# thanks to our decorator, avoiding any signal recursion
instance.skip_signal = True
instance.save()
希望这有帮助。
答案 3 :(得分:0)
您可以将相关对象的更新代码移动到MyModel.save
方法中。那么就不需要玩信号了:
class MyModel(models.Model):
some_field = #
some_key = #
def save(self, *args, **kwargs):
super(MyModel, self).save(*args, **kwargs)
for c in MyModel.objects.exclude(id=self.id).filter(some_key=self.some_key):
c.some_field = self.some_field
c.save()