Django post_save preventing recursion without overriding model save()

django, django-signals, python

Solution

What you think about this solution?

@receiver(post_save, sender=Article)
def generate_thumbnails(sender, instance=None, created=False, **kwargs):

    if not instance:
        return

    if hasattr(instance, '_dirty'):
        return

    do_something()

    try:
        instance._dirty = True
        instance.save()
    finally:
        del instance._dirty

You can also create decorator

def prevent_recursion(func):

    @wraps(func)
    def no_recursion(sender, instance=None, **kwargs):

        if not instance:
            return

        if hasattr(instance, '_dirty'):
            return

        func(sender, instance=instance, **kwargs)

        try:
            instance._dirty = True
            instance.save()
        finally:
            del instance._dirty

    return no_recursion


@receiver(post_save, sender=Article)
@prevent_recursion
def generate_thumbnails(sender, instance=None, created=False, **kwargs):

    do_something()

Problem

There are many Stack Overflow posts about recursion using the `post_save` signal, to which the comments and answers are overwhelmingly: "why not override save()" or a save that is only fired upon `created == True`. Well I believe there's a good case for not using `save()` - for example, I am adding a temporary application that handles order fulfillment data completely separate from our Order model. The rest of the framework is blissfully unaware of the fulfillment application and using post_save hooks isolates all fulfillment related code from our Order model. If we drop the fulfillment service, nothing about our core code has to change. We delete the fulfillment app, and that's it. So, are there any decent methods to ensure the post_save signal doesn't fire the same handler twice?

Original source

Related problems