53

I have the following model:

from django.db import models
from django.contrib.auth.models import User


class Profile(models.Model):
    user = models.OneToOneField(User)
    # ...

    def __unicode__(self):
        return u'%s %s' % (self.user.first_name, self.user.last_name)

When using the Django admin to delete the user, the profile gets deleted as well, which is what I want. However, when using the Django admin to delete the profile, the user does not get deleted, which is not what I want. How can I make it so that deleting the profile will also delete the user?

Nick
  • 8,049
  • 18
  • 63
  • 107

2 Answers2

77

Since Profile links to User, it is the dependent model in the relationship. Therefore when you delete a user, it deletes all dependent models. However when you delete a profile, since User does not depend on profile, it is not removed.

Unfortunately, according to on_delete Django docs, there is no on_delete rule which deletes the parent relations. In order to do that, you can overwrite the Profile's delete method:

class Profile(models.Model):
    # ...

    def delete(self, *args, **kwargs):
        self.user.delete()
        return super(self.__class__, self).delete(*args, **kwargs)

Then when doing:

Profile.objects.get(...).delete()

will also delete the profile's user. However the delete method will not be called when deleting profiles using querysets (which is what is called in Django Admin) since then Django uses SQL DELETE to delete objects in bulk:

Profile.objects.filter(...).delete()

In that case, as recommended by Django docs, you will have to use post_delete signal (docs).

from django.dispatch import receiver
from django.db.models.signals import post_delete

@receiver(post_delete, sender=Profile)
def post_delete_user(sender, instance, *args, **kwargs):
    if instance.user: # just in case user is not specified
        instance.user.delete()
Hurlu'
  • 330
  • 4
  • 13
miki725
  • 27,207
  • 17
  • 105
  • 121
  • Thanks very much! I'm still new at Django, so in case any other Django noobs find this, I had to add a dispatch_uid to the @receiver decorator in order for it to work. But after that, it worked great! – Nick Oct 08 '12 at 15:08
  • @Nick can you elaborate on your solution with dispatch_uid, because with deletion of a bulk of users it doesn't work – Gianmarco Biscini Jan 15 '20 at 10:43
  • will the signal be called when using the dropdown "delete" action, in a change list? yes it does! – benzkji May 11 '21 at 08:47
15

Use a signal on the Profile's delete method to go and delete the related User:

from django.db.models.signals import post_delete

def delete_related_user(sender, **kwargs):
    deleted_profile = kwargs['instance']
    deleted_profile.user.delete()

post_delete.connect(delete_related_user, sender=Profile)
spencer nelson
  • 4,365
  • 3
  • 24
  • 22