Search code examples
djangodjango-rest-frameworkdjango-signals

post_delete/pre_delete signals not firing for specific sender


I´ve got a model "Comment" and a signal to take actions when a comment is deleted. The signal executes when deleting the comment in the admin, but not when deleted through django-rest-framework.

@receiver(post_delete, sender=Comment, dispatch_uid=str(uuid.uuid1())) # I tried also removing dispatch_uid
def comment_post_delete(sender, instance, *args, **kwargs):

I´m not really sure if this is related to django-rest-framework but that´s how my app works. Other thing to note is that many other signals are working just fine.

All the signals are declared in a separate file signals.py and I import it at the end of models.py with a simple import signals

The only difference with other delete operations is that I´m overriding the "destroy" method of the viewset:

class CommentViewSet(mixins.CreateModelMixin,
                     mixins.DestroyModelMixin,
                     mixins.ListModelMixin,
                     viewsets.GenericViewSet):
    serializer_class = CommentSerializer
    def destroy(self, request, *args, **kwargs):
        # only the comment author or the media owner are allowed to delete
        instance = self.get_object()
        if request.user != instance.user and request.user != instance.media.owner:
            error = {'detail': 'No tienes permiso para borrar este comentario'}
            return Response(data=error, status=status.HTTP_403_FORBIDDEN)
        return super(CommentViewSet, self).destroy(request, args, kwargs)

Solution

  • post_delete and pre_delete will not be fired if the sender parameter does not match the model you are expecting.

    To check the sender, create a receiver without sender parameter:

    @receiver(post_delete)
    def comment_post_delete(sender, instance, *args, **kwargs):
        if sender == Comment:
            # do something
    

    Why could a signal get dispatched with a different model if the model being saved was "Comment"?

    This can happen when django automatically set a deferred model, so when I was expecting a "Comment" I was getting something like "Comment_deferred_somefield".

    Django automatic deferring can happen for example when the query is using Model.objects.only('field1', 'field2', 'etc') and there are some missing fields in the only() method