Могу ли я запретить Django удалять объект в зависимости от атрибута в ссылающемся типе?

Представьте 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.

Также вы можете переопределить delete метод на модели. Имейте в виду:

Преодоленные методы модели не вызываются при массовых операциях

Обратите внимание, что метод delete() для объекта не обязательно вызывается при массовом удалении объектов с помощью QuerySet или в результате каскадного удаления. Чтобы гарантировать выполнение настроенной логики удаления, вы можете использовать сигналы pre_delete и/или post_delete.

.

Вот как отменить удаление:

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()

Другим решением являются сигналы:

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")  
Вернуться на верх