After looking for a way to check if a model instance can be deleted in django, I found many options, but none was working as expected. Hope this solution can help.
Let start by creating an Abstract model class which can be inherited by other model
class ModelIsDeletable(models.Model):
name = models.CharField(max_length=200, blank=True, null=True, unique=True)
description = models.CharField(max_length=200, blank=True, null=True)
date_modified = models.DateTimeField(auto_now_add=True)
def is_deletable(self):
# get all the related object
for rel in self._meta.get_fields():
try:
# check if there is a relationship with at least one related object
related = rel.related_model.objects.filter(**{rel.field.name: self})
if related.exists():
# if there is return a Tuple of flag = False the related_model object
return False, related
except AttributeError: # an attribute error for field occurs when checking for AutoField
pass # just pass as we dont need to check for AutoField
return True, None
class Meta:
abstract = True
So let say we have three model Organization and Department and StaffType So many Department can be in an Organization And an Organization has a particular StaffType
class StaffType(ModelIsDeletable):
pensionable = models.BooleanField(default=False)
class Organization(ModelIsDeletable):
staff_type = models.ForeignKey(to=StaffType)
class Department(ModelIsDeletable):
organization = models.ForeignKey(to=Organization, to_field="id")
so let say after adding some information you want to remove an organization model instance that is already tied to a Department
For instance we have Organization Table => (name = Engineering, pk = 1) Department Table => (name=Developer, organization_fk=1, pk=1)
Now when you try to delete an organization after get it with the pk
a_org = Organization.objects.get(pk=1)
With this at hand you can check if it deletable
deletable, related_obj = a_org.is_deletable()
if not deletable:
# do some stuff with the related_obj list
else:
# call the delete function
a_org.delete()
Your question appears to be "How to detect what related model objects would be deleted if I delete this model object?" or "How to detect what related rows would be deleted if I delete this row?"
Another option is to use a transaction, do the delete, save the information provided by django, but rollback before committing the change. This works in databases like Postgres and MySQL, but I don't know about others.
In this example I want to know what will be deleted if I delete my organization named 'pdemo', and I see that it has 408 related Property objects.
https://gist.github.com/cgthayer/25aa97bb4b74efb75e3467fb7bbdaacb
>>> from django.db import transaction
>>> transaction.set_autocommit(autocommit=False)
>>> o = Organization_v2.objects.get(name='pdemo')
>>> del_info = o.delete()
>>> del_info
(1404, {'data.Property': 408, [..more stuff..], 'data.Organization_v2': 1})
>>> Property.objects.filter(scope__organization_id=o).count()
0
>>> transaction.rollback()
>>> o = Organization_v2.objects.get(name='pdemo')
>>> Property.objects.filter(scope__organization_id=o).count()
408
This could be translated into a generic function.
When looking into this, I found many old solutions that use the functions in the django.contrib.admin to determine this, but that's an undocumented api that seems to change from time to time, so using transactions seems to be easier iff your database supports it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With