Search code examples
pythondjangodjango-modelsdjango-signals

post_save.disconnect does not work at all


I'm trying to make Django not to send signal in one case. When adding a new instance of model Delivery (right after creating a Job) as an attribute of model Job, I don't want to send signal because the signal should alert admin that Job has been edited.

Unfortunately I can't make it work.

@receiver(post_save,sender=Job) # When Job is created or edited
def alert_admin(sender,instance,created,**kwargs):
    if created:
        email.AdminNotifications.new_order(instance)
    else:
        email.AdminNotifications.edited_order(instance)

@receiver(post_save,sender=Job) # When job is created, I want to create a delivery object as an attribute of Job
def create_delivery(sender,instance,created,**kwargs):
    if created:
        delivery,created_delivery = Delivery.objects.get_or_create(job=instance)
        instance.delivery = delivery
        delivery.save()
        post_save.disconnect(alert_admin)
        instance.save() # I DONT WANT TO SEND SIGNAL IN THIS CASE
        post_save.connect(alert_admin)

Where is the problem? I did this but I still recieve two alerts - New Order and Edited Order.


Solution

  • The problem is that you are listening to the same signal twice.

    @receiver(post_save,sender=Job) # When Job is created or edited
    def alert_admin(sender,instance,created,**kwargs):
        ###
    
    @receiver(post_save,sender=Job):
    def create_delivery(sender,instance,created,**kwargs):
       ###
    

    You are assuing that create_delivery will be called first. But that does not seem to happen. alert_admin appears to be called first. So what ever signal disabling that you do in create_delivery just goes waste.

    Django does not provide any guarantees or controls over the order in which signals are fired (what's the order of post_save receiver in django?)

    You can add a simple flag to your instance to tell the signal processor that this signal does not need further processing.

    if hasattr(instance,'signal_processed'):
         return
    else:
        # do whatever processing
        instance.signal_processed = True