Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show related items using DeleteView in Django?

I am doing a view to delete (using the generic view DeleteView from Django) an instance from a model, but it cascades and deletes instances from other models:

url(r'^person/(?P<pk>\d+)/delete/$', login_required(DeleteView.as_view(model=Person, success_url='/person/', template_name='delete.html')), name='person_delete'),

What I want to do is to show the list of related items that are going to be deleted, as the admin interface does, like:

Are you sure you are going to delete Person NAMEOFTHEPERSON?
By deleting it, you are also going to delete:
CLASSNAME1: CLASSOBJECT1 ; CLASSNAME2: CLASSOBJECT2 ; CLASSNAME3: CLASSOBJECT3 ; etc
like image 792
staticdev Avatar asked Aug 28 '12 11:08

staticdev


People also ask

What is a delete view in Django?

DeleteView – Class Based Views Django Last Updated : 24 Jun, 2021 Delete View refers to a view (logic) to delete a particular instance of a table from the database. It is used to delete entries in the database for example, deleting an article at geeksforgeeks.

What are class-based views in Django?

We have already discussed basics of Delete View in Delete View – Function based Views Django. Class-based views provide an alternative way to implement views as Python objects instead of functions. They do not replace function-based views, but have certain differences and advantages when compared to function-based views:

How to delete a specific object from a database table in Django?

Since we are getting a specific object of a database table to delete, we use the built-in get_object_or_404 function in Django. This allows us to get a specific object from the database table that we can delete. Since we are working with the Movie database table, we import Movie from models.py

How to delete a deleteview on a GET request?

The DeleteView won't delete on GET requests; this is your opportunity to provide a confirmation template (you can provide the name in the template_name class attribute) with a "Yes I'm sure" button which POST s to this view.


2 Answers

You can use the Collector class Django uses to determine what objects to delete in the cascade. Instantiate it and then call collect on it passing the objects you intend to delete. It expects a list or queryset, so if you only have one object, just put in inside a list:

from django.db.models.deletion import Collector  collector = Collector(using='default') # or specific database collector.collect([some_instance]) for model, instance in collector.instances_with_model():     # do something 

instances_with_model returns a generator, so you can only use it within the context of a loop. If you'd prefer an actual data structure that you can manipulate, the admin contrib package has a Collector subclass called NestedObjects, that works the same way, but has a nested method that returns a hierarchical list:

from django.contrib.admin.utils import NestedObjects  collector = NestedObjects(using='default') # or specific database collector.collect([some_instance]) to_delete = collector.nested() 

Updated: Since Django 1.9, django.contrib.admin.util was renamed to django.contrib.admin.utils

like image 198
Chris Pratt Avatar answered Sep 21 '22 06:09

Chris Pratt


I use a cutdown modifcation of get_deleted_objects() from the admin and use it to extend my context in get_context in the delete view:

define somewhere

from django.contrib.admin.utils import NestedObjects from django.utils.text import capfirst from django.utils.encoding import force_text  def get_deleted_objects(objs):      collector = NestedObjects(using='default')     collector.collect(objs)     #     def format_callback(obj):         opts = obj._meta         no_edit_link = '%s: %s' % (capfirst(opts.verbose_name),                                    force_text(obj))         return no_edit_link                 #     to_delete = collector.nested(format_callback)     protected = [format_callback(obj) for obj in collector.protected]     model_count = {model._meta.verbose_name_plural: len(objs) for model, objs in collector.model_objs.items()}     #     return to_delete, model_count, protected 

then in your views

from somewhere import get_deleted_objects # class ExampleDelete(DeleteView):     # ...     def get_context_data(self, **kwargs):         #         context = super().get_context_data(**kwargs)         #         deletable_objects, model_count, protected = get_deleted_objects([self.object])         #         context['deletable_objects']=deletable_objects         context['model_count']=dict(model_count).items()         context['protected']=protected         #         return context 

now you can use them in your template

<table>   <tr>     <th>Name</th>     <th>Amount</th>   </tr>   {% for model_name, object_count in model_count %}     <tr>       <td>{{ model_name|capfirst }}</td>       <td>{{ object_count }}</td>     </tr>   {% endfor %} </table> <p>   <ul>     {{ deletable_objects|unordered_list }}   </ul> </p> 

Most is just copy/paste/edit/delete unwanted from django admin

like image 41
JRM Avatar answered Sep 22 '22 06:09

JRM