How can I prevent post_save recursion in Django?

后端 未结 4 457
猫巷女王i
猫巷女王i 2020-12-16 04:59

I have some problems when using signal in Django.

post_save occurs recursion because of instance.save() inside of function.

相关标签:
4条回答
  • 2020-12-16 05:44

    If you want to avoid recursion in post_save signal, just use Model.objects.filter(id=id).update(object=object)

    0 讨论(0)
  • 2020-12-16 05:51

    Disconnect the signal before save, then connect again. https://docs.djangoproject.com/en/1.10/topics/signals/#disconnecting-signals

    def post_save_product(sender, instance, **kwargs):
        post_save.disconnect(post_save_product, sender=sender)
        instance.do_stuff()
        instance.save()
        post_save.connect(post_save_product, sender=sender)
    post_save.connect(post_save_product, sender= Product)
    
    0 讨论(0)
  • 2020-12-16 05:52

    Just use pre_save , you don't need to use .save() method inside it again.

    0 讨论(0)
  • 2020-12-16 06:00

    In the second case, you are comparing the database value of instance.color to the display value. These will never match. You should check against the database value instead:

    @receiver(post_save, sender=Variation)
    def post_save_variation(sender, instance, created, **kwargs):
        if not instance.price:
            if instance.color == 'black':
                instance.price = 40000
            elif instance.color == 'single':
                instance.price = 50000
            elif instance.color == 'multi':
                instance.price = 60000
            instance.save()
    

    Similarly you should set the default to the database value, i.e. default = 'black'.

    In your original code, all the checks will fail, and instance.price is never updated to a non-empty value. The call to instance.save() will trigger the post_save signal again, not instance.price is still true, and the instance is saved again without setting the price. This is the infinite recursion you're seeing.

    In the first example, the slug is always set to a non-empty value, so when the post_save signal is triggered the second time, the if not instance.slug check will fail, and the instance will not be saved a third time.

    In both cases you're saving the instance at least twice if the slug/price is not set. To prevent this, you can use the pre_save signal. You won't have to save the instance again in the signal handler:

    @receiver(pre_save, sender=Variation)
    def pre_save_variation(sender, instance, **kwargs):
        if not instance.price:
            if instance.color == 'black':
                instance.price = 40000
            elif instance.color == 'single':
                instance.price = 50000
            elif instance.color == 'multi':
                instance.price = 60000
    
    0 讨论(0)
提交回复
热议问题