我可以防止 Django 根据引用类型中的属性删除对象吗?

Can I prevent Django from deleting an object depending on an attribute in a referencing type?

想象一下 PetOwner 和一个 Pet 模型:

class PetOwner(models.Model):
  name = models.CharField()

class Pet(models.Model):
  owner = models.ForeignKey('PetOwner', on_delete=models.CASCADE)
  alive = models.BooleanField(default=True)

我希望可以删除 PetOwners,但前提是他们的所有相关宠物都不再活着。如果是这样,则可以删除 PetOwner,同时删除他所有关联的宠物(级联语义)。

这可能吗?

您正在谈论设置 'business rule'。您可以在多个地方写下您的 'business rules',例如,在删除 PetOwners.

的每个视图或进程中

此外,您可以在模型上使用 override delete 方法。请记住:

Overridden model methods are not called on bulk operations

Note that the delete() method for an object is not necessarily called when deleting objects in bulk using a QuerySet or as a result of a cascading delete. To ensure customized delete logic gets executed, you can use pre_delete and/or post_delete signals.

这是覆盖删除的方法:

from django.core.exceptions import PermissionDenied

class PetOwner(models.Model):

  # ...

  def delete(self):
    has_pets_alive = self.pet_set.filter(alive=True).exists()
    if has_pets_alive:
        raise PermissionDenied("This owner has pets alive")        
    super(PetOwner, self).delete()

另一个解决方案是signals:

from django.db.models.signals import pre_delete 
from django.dispatch import receiver
    
@receiver(pre_delete, sender=PetOwner)
def check_pets_alive(sender, instance, **kwargs):
    has_pets_alive = instance.pet_set.filter(alive=True).exists()
    if has_pets_alive:
        raise PermissionDenied("This owner has pets alive")