Django List objects that will be deleted by deleting the current object

Viewed 1559

In my DeleteView template, I'd like to warn the user that deleting the current object will delete the following objects (since the db schema requires on_delete = models.CASCADE).

Here is an example model:

class Book(models.Model):
    course = models.ForeignKey(Course, related_name = 'course_books', on_delete = models.CASCADE, null = True, blank = True)

class Exercise(models.Model):
    book = models.ForeignKey(Book, related_name = 'exercises', on_delete = models.CASCADE, null = True, blank = True)
    ...

class Solution(models.Model):
    exercise = models.ForeignKey(Exercise, related_name = 'solutions', on_delete = models.CASCADE, null = True, blank = True)

So, say the user wants to delete a course, I'd like to warn the user which books, exercises, and solutions will be deleted upon deleting the current book. Something to this effect:

WARNING: Deleting course Programming 101 will delete Python Programming for Beginners and Python By Example.  It will also delete Excersises 1-5 and solutions 1-10

This will require that I can look at the related field to see if the on_delete is set to CASCADE or not. If it is, I should add it to the list of to_be_deleted objects.

I have looked to see if I can check the on_delete attribute of the field:

for related_object in the_course._meta.related_objects:
    dir(related_object.field)

But nothing shows up to help so I'm reaching out here...

2 Answers

You can do so doing

from django.contrib.admin.utils import NestedObjects
from django.db import DEFAULT_DB_ALIAS

collector = NestedObjects(using=DEFAULT_DB_ALIAS)
collector.collect([obj])
print(collector.nested())

You can filter the objects with that particular object_id. For example:

qs = Solution.objects.filter(exercise__book__course_id=course_id).select_related('exercise__book')

This will give a queryset of all the objects of Solution with related foreign key objects exercise and book. Then you can loop through this queryset and check instance._meta.app_label to differentiate between the objects.

Related