django:使用保存后信号的递归

时间:2010-07-14 13:48:09

标签: django recursion save signals

情况如下:

假设我在django中有一个模型A.当我保存一个对象(A类)时,我需要将它的字段保存到该类的所有其他对象中。我的意思是我需要每个其他A对象都是lat保存的副本。

当我使用信号(例如后保存)时,我得到一个递归(对象试图相互保存,我猜)并且我的python死了。

我是男性我希望在保存前/后信号中对同一个类使用.save()方法会导致递归但只是不知道如何避免它。

我们做什么?

3 个答案:

答案 0 :(得分:7)

@ShawnFumo如果同一时间将同一模型保存在其他地方,则断开信号是危险的,不要这样做!

@Aram Dulyan,您的解决方案有效,但阻止您使用功能强大的信号!

如果你想避免递归并继续使用signals(),一个简单的方法是在当前实例上设置一个属性,以防止即将发出的信号。

这可以使用一个简单的装饰器来完成,该装饰器检查给定的实例是否具有' 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):
    # you processing
    pass

m = MyModel()
# Here we flag the instance with 'skip_signal'
# and my_model_post_save won't be called
# thanks to our decorator, avoiding any signal recursion
m.skip_signal  = True
m.save()

希望这有帮助。

答案 1 :(得分:5)

这将有效:

class YourModel(models.Model):
    name = models.CharField(max_length=50)

    def save_dupe(self):
        super(YourModel, self).save()

    def save(self, *args, **kwargs):
        super(YourModel, self).save(*args, **kwargs)
        for model in YourModel.objects.exclude(pk=self.pk):
            model.name = self.name
            # Repeat the above for all your other fields
            model.save_dupe()

如果你有很多字段,你可能希望在将它们复制到另一个模型时迭代它们。我会留给你的。

答案 2 :(得分:5)

另一种处理方法是在保存时删除监听器。所以:

class Foo(models.Model):
  ...

def foo_post_save(instance):
  post_save.disconnect(foo_post_save, sender=Foo)
  do_stuff_toSaved_instance(instance)
  instance.save()
  post_save.connect(foo_post_save, sender=Foo)

post_save.connect(foo_post_save, sender=Foo)