Это будет решение из реализации в моем приложении.Код выглядит следующим образом: LWN-ответ.
Ваши данные удаляются в 4 ситуациях:
- SQL-запрос
- Вызов
delete()
для экземпляра модели: project.delete()
- Вызов
delete()
для экземпляра QuerySet: Project.objects.all().delete()
- Удалено полем ForeignKey для другой модели
Пока ничего нетмногое вы можете сделать с первым случаем, остальные три могут быть хорошо контролируемыми.Один совет заключается в том, что в большинстве случаев вы никогда не должны удалять сами данные, потому что эти данные отражают историю и использование нашего приложения.Параметр active
Вместо этого предпочтительным является логическое поле.
Чтобы предотвратить delete()
в экземпляре модели, подкласс delete()
в объявлении модели:
def delete(self):
self.active = False
self.save(update_fields=('active',))
Пока delete()
в QuerySetЭкземпляр нуждается в небольшой настройке с помощью диспетчера пользовательских объектов, как в ответе LWN.
Оберните это в многократно используемую реализацию:
class ActiveQuerySet(models.QuerySet):
def delete(self):
self.save(update_fields=('active',))
class ActiveManager(models.Manager):
def active(self):
return self.model.objects.filter(active=True)
def get_queryset(self):
return ActiveQuerySet(self.model, using=self._db)
class ActiveModel(models.Model):
""" Use `active` state of model instead of delete it
"""
active = models.BooleanField(default=True, editable=False)
class Meta:
abstract = True
def delete(self):
self.active = False
self.save()
objects = ActiveManager()
Использование, просто подкласс ActiveModel
class:
class Project(ActiveModel):
...
Тем не менее, наш объект все еще можно удалить, если удаляется любое из его полей ForeignKey:
class Employee(models.Model):
name = models.CharField(name, unique=True)
class Project(models.Model):
name = models.CharField(name, unique=True)
manager = purchaser = models.ForeignKey(
Employee, related_name='project_as_manager')
>>> manager.delete() # this would cause `project` deleted as well
Этого можно избежать, добавив аргумент on_delete поля модели:
class Project(models.Model):
name = models.CharField(name, unique=True)
manager = purchaser = models.ForeignKey(
Employee, related_name='project_as_manager',
on_delete=models.PROTECT)
Значение по умолчанию on_delete
равно CASCADE
, что приведет к удалению вашего экземпляра, с помощью PROTECT
вместо этого будет поднят ProtectedError
(подкласс * 1053).*).Другая цель этого состоит в том, что ForeignKey данных должен быть сохранен как ссылка.