Django: recursion using signal after save

Here's the situation:

Say I have a model A in django. When I save an object (class A), I need to save it on all other objects of this class. I mean, I need any other object A to be a copy of the saved armor.

When I use signals (for example, after saving), I get recursion (objects try to save each other, I think), and my python dies.

I expected that using the .save () method in the same class in the pre / post-save signal would lead to recursion, but just didn't know how to avoid it.

What should we do?

+5
source share
3 answers

This will work:

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()

, , , . .

+4

@ShawnFumo , , !

@Aram Dulyan, , , !

(), - , .

, , '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()

, .

+7

- . :

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)
+4

All Articles