Deleting Records (delete, soft-delete patterns)
Django provides delete() for permanent deletion. For production apps, soft-delete (marking records as deleted without actually removing them) is often preferred — it allows recovery and maintains referential integrity.
15 min•By Priygop Team•Updated 2026
Delete Methods
- obj.delete() — Delete single object
- QuerySet.delete() — Bulk delete
- on_delete=CASCADE — Automatically deletes related objects
- on_delete=PROTECT — Prevents deletion if related objects exist
- Soft-delete: Add is_deleted field, override manager/delete
- Django signals: pre_delete, post_delete for cleanup
- delete() returns count of deleted objects
Delete & Soft-Delete
Delete & Soft-Delete
# Hard delete — permanent
# post = Post.objects.get(pk=1)
# post.delete() # Permanently removed from database
# Bulk delete
# Post.objects.filter(published=False).delete()
# Returns: (5, {'blog.Post': 5}) # 5 posts deleted
# Soft-delete pattern (recommended for production)
# class Post(models.Model):
# title = models.CharField(max_length=200)
# is_deleted = models.BooleanField(default=False)
# deleted_at = models.DateTimeField(null=True, blank=True)
#
# # Override delete for soft-delete
# def delete(self, *args, **kwargs):
# self.is_deleted = True
# self.deleted_at = timezone.now()
# self.save()
#
# # Hard delete when needed
# def hard_delete(self):
# super().delete()
# Custom manager to exclude deleted records
# class ActiveManager(models.Manager):
# def get_queryset(self):
# return super().get_queryset().filter(is_deleted=False)
# class Post(models.Model):
# # ...
# objects = ActiveManager() # Default: only active
# all_objects = models.Manager() # Include deleted
# Post.objects.all() # Only non-deleted
# Post.all_objects.all() # Everything including deletedTip
Tip
Override clean_fieldname() for field-specific validation and clean() for cross-field validation (e.g., password confirmation).
Diagram
Loading diagram…
QuerySets are LAZY — no DB hit until evaluated.
Common Mistake
Warning
Raising ValidationError without proper error messages. Always include clear, user-friendly error descriptions.
Practice Task
Note
(1) Add custom clean_email() validation. (2) Add cross-field validation in clean(). (3) Display error messages.
Quick Quiz
Key Takeaways
- Django provides delete() for permanent deletion.
- obj.delete() — Delete single object
- QuerySet.delete() — Bulk delete
- on_delete=CASCADE — Automatically deletes related objects