Django soft delete Model using Managers

Photo by Sam Pak on Unsplash

Django soft delete Model using Managers

Below is the soft delete model you can inherit from. It uses an active field which on delete, it will only set to False and not actually delete the records from the overriden delete method. There is a provision available to actually delete records. It can be used in a cronjob to recover space etc.

class SoftDeleteModel(models.Model):
    active = models.BooleanField(default=True, db_index=True)

    class Meta:
        abstract = True

    def delete(self, *args, **kwargs):  # pylint: disable=unused-argument
        if kwargs.pop('hard', False):
            return super().delete(*args, **kwargs) = False'active',))
        return (0, {self._meta.model_name: 0})

One could use a datetime which indicates inactive records if set. It would also record the time when the delete occurred

The ActiveQuerySet overrides the delete method to allow for bulk delete. The corresponding manager uses the override so only active records are included. An InactiveManage which inherits from the default Manger is included for completeness.

class ActiveQuerySet(models.QuerySet):
    def delete(self, *args, **kwargs):
        if kwargs.pop('hard', False):
            return super().delete(*args, **kwargs)
        return self.update(active=False)

class ActiveManager(models.Manager):
    def get_queryset(self):
        return ActiveQuerySet(self.model, using=self._db).exclude(active=False)

class InActiveManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().exclude(active=True)

Here's and example of it all put together.

from django.db import models

class Textbooks(models.Model, SoftDeleteModel):
    id = models.UUIDField(db_index=True)

    objects = ActiveManager()
    deleted_objects = InActiveManager()
    all_objects = models.Manager()

Notice that the default objects is overriden to only provide active records for all ORM actions.