3

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...

EarlyCoder
  • 1,213
  • 2
  • 18
  • 42

3 Answers3

7

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())
Julien Kieffer
  • 1,116
  • 6
  • 16
  • I had to move to another part of the project. I am revisiting the DeleteView and ran your code. When I type `the_project = Project.objects.filter(name__icontains = 'some_name')` I get `AttributeError: 'QuerySet' object has no attribute '_meta'` I did run `help(collector.collect)`, and it does say that I have to pass QuerySet to it, but I still get the error – EarlyCoder Dec 21 '19 at 22:20
0

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.

Nalin Dobhal
  • 2,292
  • 2
  • 10
  • 20
  • This solution works but it is a way around solution because you would have to know the related object and do all the work by hand. On a site where the relationships are across multiple apps, it is not practical. So, your solution is much appreciated and helpful, but I will wait for another solution for now – EarlyCoder Oct 02 '19 at 21:06
  • ok then you should edit your question so that it will be active again, otherwise it won't get enough attention. – Nalin Dobhal Oct 03 '19 at 06:53
0

Maybe this is a duplicated question with How can I check what objects will be cascade deleted in Django?. So I paste the same answer:

I suggest using the NestedObjects util provided in django admin.

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

using = router.db_for_write(Item._meta.model)
# if you only have one database, just set using = "default"

nested_object = NestedObjects(using)
nested_object.collect([Item])
# If you want to delete multi item, you can use:
# nested_object.collect(Model.objects.filter(type="deleted"))

print(nested_object.nested()

The result look like this: example result

ramwin
  • 5,803
  • 3
  • 27
  • 29