Skip to main content

Soft deletion

SoftDeletableModel adds a removed_at timestamp. Deleting an instance stamps it instead of removing the row.

from blueprint.models import SoftDeletableContentModel


class Page(SoftDeletableContentModel):
title = models.CharField(max_length=200)


page = Page.objects.create(title="About")
page.delete() # soft: stamps removed_at
page.delete(soft=False) # hard: really deletes the row

Two managers​

Every soft-deletable model gets two managers:

  • objects — sees everything, including removed instances.
  • available_objects — filters out removed instances.
page.delete()
Page.objects.filter(pk=page.pk).exists() # True
Page.available_objects.filter(pk=page.pk).exists() # False

The is_removed property reflects the current state.

Bulk deletion​

QuerySet.delete() soft-deletes as well:

Page.objects.filter(title__startswith="Draft").delete()
caution

Cascade deletes driven by Django's deletion collector still hard-delete soft-deletable models — Django bypasses QuerySet.delete() on its fast delete path. If you rely on soft deletion, avoid cascades from non-soft-deletable parents, or override the cascade behavior in your model.