How to trigger Django's pre_delete signal?

Viewed 314

I have a User model and a UserImage model that contains a foreign key to a User. The foreign key is set to CASCADE delete.

Here is what the receivers look like in my models.py:

@receiver(pre_delete, sender=User)
def deleteFile(sender, instance, **kwargs):
    print("User pre_delete triggered")
    instance.thumbnail.delete()

@receiver(pre_delete, sender=UserImage)
def deleteFile(sender, instance, **kwargs):
    print("UserImage pre_delete triggered")
    instance.image.delete()

When I execute the following lines of code:

>>> User.objects.last().delete()
"UserImage pre_delete triggered"

For some reason the associated UserImage signal is being received but the actual User model's signal is not.

Am I missing something?

1 Answers

If you read the documentation carefully you will see that the delete() method on a model will execute purely in SQL (if possible). So the delete() method on UserImage will not be called by Django, thus the signal will not be triggered. If you want it to be triggered you could override the delete method on your User model to also call the delete() on the related object. Something like this:

class User(models.Model):
    def delete(self, using=None):
        self.userimage_set.all().delete()
        super().delete(using=using)

UPDATE:

I did not read the question correctly so I have to update my answer. I think what is happening is that both signals have the same name and thus the first one is overwritten by the second one, and thus only the second one is executed. I would suggest changing the function name to something else and see if that changes things.

Related