Soft Deletion in Django

To Nha Notes | March 3, 2021, 11:40 a.m.

The difference between soft-delete and hard-delete is: for hard-delete, its data is actually deleted, we can not recover then. For soft-delete, we just update a field named deleted_at to timezone.now() instead. So that we can recover it as needed.

To implement it, we need to inherit to customize Django base classes of models, managers and queryset to exclude the deleted data which has deleted_at is updated.

The model for soft delete:

class SoftDeletionModel(models.Model):
    deleted_at = models.DateTimeField(blank=True, null=True)

    objects = SoftDeletionManager()
    all_objects = SoftDeletionManager(alive_only=False)

    class Meta:
        abstract = True

    def delete(self):
        self.deleted_at = timezone.now()
        self.save()

    def hard_delete(self):
        super(SoftDeletionModel, self).delete()

The manager class for soft delete:

class SoftDeletionManager(models.Manager):
    def __init__(self, *args, **kwargs):
        self.alive_only = kwargs.pop('alive_only', True)
        super(SoftDeletionManager, self).__init__(*args, **kwargs)

    def get_queryset(self):
        if self.alive_only:
            return SoftDeletionQuerySet(self.model).filter(deleted_at=None)
        return SoftDeletionQuerySet(self.model)

    def hard_delete(self):
        return self.get_queryset().hard_delete()

The QuerySet for soft delete:

class SoftDeletionQuerySet(QuerySet):
    def delete(self):
        return super(SoftDeletionQuerySet, self).update(deleted_at=timezone.now())

    def hard_delete(self):
        return super(SoftDeletionQuerySet, self).delete()

    def alive(self):
        return self.filter(deleted_at=None)

    def dead(self):
        return self.exclude(deleted_at=None)

See more detail in the blog: Soft Deletion in Django