Stevy
Stevy

Reputation: 3387

Django: prevent deleting child model unless parent model is deleted

I have 2 models (I left out the __str__ representation for the sake of simplicity).

Customer:

# models.py

class Customer(models.Model):
    customer_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, 
                                     editable=False, db_index=True)
    customer_name = models.CharField(max_length=128)

and Device_group:

# models.py

class Device_group(models.Model):
    group_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, 
                                  editable=False, db_index=True)
    customer_uuid = models.ForeignKey(Customer, on_delete=models.CASCADE)
    device_group_name = models.CharField(max_length=20)
    color = models.CharField(max_length=8)
    is_default = models.BooleanField(default=False)

Each Customer can only have 1 Device_group that is default. I want to be able to prevent the default group from being deleted when the Customer still exists. However, when the Customer is deleted, all device groups, including the default group should be deleted.

To prevent the default group from being deleted I use the pre_delete signal like this:

# signals.py

@receiver(pre_delete, sender=Device_group)
def protect_default_group(sender, instance, **kwargs):
    if instance.is_default:
        raise ProtectedError('The default group cannot be deleted.', instance)                        

This raises a ProtectedError and prevents deletion when the user tries to delete the default group from the Device_group model in Django Admin.

To make sure all device groups, including the default group, are deleted upon deletion of the Customer, I tried to use another pre_delete signal to change the is_default field to False and delete the group like this:

# signals.py

@receiver(pre_delete, sender=Customer)
def unprotect_default_group(sender, instance, **kwargs):
    default_group = Device_group.objects.get(customer_uuid=instance, is_default=True)                                         
    default_group.is_default=False
    default_group.delete()

When trying to delete a Customer who has a default Device_group, it results in the ProtectedError.

How do I make sure that upon deletion of the Customer always all device groups are deleted without throwing the ProtectedError. But deleting a Device_group is prevented when it is the default group?

I am using Python 3.7.2 and Django 2.1.7

Thanks

Upvotes: 2

Views: 1384

Answers (2)

Stargazer
Stargazer

Reputation: 1530

Change your on_delete action:

customer_uuid = models.ForeignKey(Customer, on_delete=models.DO_NOTHING)

Then tweak your signal.

@receiver(pre_delete, sender=Customer)
def unprotect_default_group(sender, instance, **kwargs):
    Device_group.objects.filter(customer_uuid=instance,
    is_default=False).delete()

Upvotes: 2

Jibin Mathews
Jibin Mathews

Reputation: 1135

After default_group.is_default=False you need to save it by default_group.save()

Upvotes: 0

Related Questions