Это завершит решение из реализации в моем приложении. Некоторый код представляет собой ответ 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 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
(подкласс IntegrityError
). Другая цель этого заключается в том, что внешний ключ данных должен храниться в качестве ссылки.
person
anhdat
schedule
07.07.2016