Короткий ответ
Soft delete — это помечание записи как удалённой через флаг (is_deleted) или метку времени (deleted_at) вместо физического удаления строки; это сохраняет историю и возможность восстановления, но требует, чтобы вся логика приложения и все запросы явно учитывали этот флаг, иначе «удалённые» записи будут неожиданно появляться в выборках.
Как это работает подробнее
Вместо DELETE FROM table WHERE id = ... выполняется UPDATE table SET deleted_at = now() WHERE id = ...; все последующие SELECT-запросы обязаны добавлять условие WHERE deleted_at IS NULL, либо это делает кастомный менеджер ORM.
Пример кода
example.py
class ActiveUserManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(deleted_at__isnull=True)
class User(models.Model):
email = models.EmailField()
deleted_at = models.DateTimeField(null=True, blank=True)
objects = ActiveUserManager()
all_objects = models.Manager()
def soft_delete(self):
self.deleted_at = timezone.now()
self.save(update_fields=["deleted_at"])Что использовать на практике
- Практика. Soft delete уместен там, где важна аудируемость и возможность восстановления, или где на удалённую запись продолжают физически ссылаться другие таблицы; индексы нужно проектировать с учётом фильтра (partial index WHERE deleted_at IS NULL).
Подводные камни
- Ошибка. Забывают добавить фильтр по deleted_at в одном из мест кода (прямой SQL, отдельный отчёт); не продумывают UNIQUE-ограничения — повторная регистрация с тем же email после soft delete может упереться в unique-constraint без partial unique index.