这将在我的应用程序中完成解决方案。一些代码是LWN's answer.
您的数据被删除有四种情况:
- SQL 查询
- 在模型实例上调用
delete():project.delete()
- 在 QuerySet 实例上调用
delete():Project.objects.all().delete()
- 已被其他模型上的 ForeignKey 字段删除
虽然您对第一种情况无能为力,但可以对其他三种情况进行细粒度控制。
一个建议是,在大多数情况下,您永远不应该删除数据本身,因为这些数据反映了我们应用程序的历史和使用情况。首选设置 active 布尔字段。
为了防止模型实例上出现delete(),请在模型声明中将delete() 子类化:
def delete(self):
self.active = False
self.save(update_fields=('active',))
虽然 QuerySet 实例上的 delete() 需要像 LWN's answer. 那样使用自定义对象管理器进行一些设置
将其包装成一个可重用的实现:
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
这可以通过在 Model 字段中添加on_delete argument 来防止:
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 的子类)。这样做的另一个目的是要保留数据的 ForeignKey 作为参考。