Login

Add delete buttons to admin changelist

Author:
kylefox
Posted:
May 26, 2007
Language:
HTML/template
Version:
Not specified
Score:
10 (after 10 ratings)

This adds a checkbox for each object and three buttons to a model's change list:

  1. Delete selected: deletes the selected objects

  2. Delete shown: deletes all the visible objects. For example, if you perform a search or in any way filter the list, this button deletes only objects that were filtered.

  3. Delete all: Deletes all instances of the model, including those not shown (if looking at a filtered list).

The deletes perform no confirmation -- once you hit the buttons the models are gone, so maybe don't use (or add a confirmation screen) for really sensitive stuff.

  • uses django oldforms-admin (ie 0.96)
  • works fine if you include a search_fields list in the Admin class
  • code for the view could probably be refactored a bit :)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
###   MODEL: Include something like this in your model   ###
class Person(models.Model):

    class Admin:
        list_display = ['name', 'select']

    name = models.CharField(maxlength=100)

    def select(self):
        return '<input type="checkbox" name="person" value="%s"/>' % self.id
    select.allow_tags = True
    select.short_description = ''



###   TEMPLATE: 'change_list.html'   ###
###   Put it in either admin/change_list.html, admin/<app>/<model>/change_list.html, etc   ###
{% extends "admin/change_list.html" %}

{% block result_list %}
<form action="delete/" method="post">
    {{ block.super }}
    {% for r in cl.get_query_set %}
        <input type="hidden" name="qs_obj" value="{{ r.id }}" id="qs_obj_{{ r.id }}">
    {% endfor %}
    <p>
        <input type="submit" name="delete_selected" id="id_delete_selected" value="Delete selected" />
        <input type="submit" name="delete_shown" id="id_delete_shown" value="Delete shown" />               
        <input type="submit" name="delete_all" id="id_delete_all" value="Delete all" /> 
    </p>
</form> 
{% endblock %}



###  VIEW: I just tossed this in 'admin.py' in the project root   ###
from django.contrib.admin.views.main import *

def delete(request, app_label, model_name):
    
    model = models.get_model(app_label, model_name)
    opts = model._meta  
    if model is None:
        raise Http404("App %r, model %r, not found" % (app_label, model_name))
    if not request.user.has_perm(app_label + '.' + model._meta.get_change_permission()):
        raise PermissionDenied  
    try:
        cl = ChangeList(request, model)
    except IncorrectLookupParameters:
        if ERROR_FLAG in request.GET.keys():
            return render_to_response('admin/invalid_setup.html', {'title': _('Database error')})
        return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')

    if 'delete_selected' in request.POST and model_name in request.POST:
        deleted = []
        for obj in cl.get_query_set().filter(id__in=request.POST.getlist(model_name)):
            obj.delete()
            deleted.append('"%s"' % str(obj))
        request.user.message_set.create(message=_('The %(name)s %(obj)s were deleted successfully.') % {'name': opts.verbose_name_plural, 'obj': ", ".join(deleted)})

    if 'delete_shown' in request.POST and 'qs_obj' in request.POST:
        deleted = []
        for obj in cl.get_query_set().filter(id__in=request.POST.getlist('qs_obj')):
            obj.delete()
            deleted.append('"%s"' % str(obj))
        request.user.message_set.create(message=_('The %(name)s %(obj)s were deleted successfully.') % {'name': opts.verbose_name_plural, 'obj': ", ".join(deleted)})
        
    if 'delete_all' in request.POST and cl.get_query_set().count() > 0:
        for obj in cl.get_query_set():
            obj.delete()
        request.user.message_set.create(message=_('All %(name)s were deleted successfully.') % {'name': opts.verbose_name_plural})      
    
    return HttpResponseRedirect('..')
change_list = staff_member_required(never_cache(change_list))



###   URLS: Add this line to your urls BEFORE the normal admin urls line   ###
    ('^admin/([^/]+)/([^/]+)/delete/$', 'admin.delete'),

More like this

  1. Bootstrap Accordian by Netplay4 7 years, 9 months ago
  2. Bootstrap theme for django-endless-pagination? by se210 10 years, 9 months ago
  3. Bootstrap theme for django-endless-pagination? by se210 10 years, 9 months ago
  4. Reusable form template with generic view by roldandvg 10 years, 10 months ago
  5. Pagination Django with Boostrap by guilegarcia 11 years ago

Comments

bfrederi (on October 1, 2007):

On line 54, delete_selected seems to be failing on the condition "model_name in request.POST:". model_name doesn't appear anywhere in request.POST when I attempt to remove an item.

#

bfrederi (on October 1, 2007):

Ok, sorry I see what you did now: class Person(models.Model): return '<input type="checkbox" name="person" value="%s"/>' % self.id

You named the input checkbox the same as the model. My mistake.

#

bfrederi (on October 3, 2007):

I added a bit to your snippet to allow the user to select all and un-select all by use of a check box next to the Delete field and some Jquery. Here is the Jquery: $("#checkboxall").click(function(){ var checked_status = this.checked; $("input[@name=person]").each(function(){ this.checked = checked_status; }); }); Then add this to the short description: select.short_description = 'Delete <input type="checkbox" id="checkboxall" name="check_all" value="Check All" />' I thought this would help some people. Great snippet. Very useful.

#

bfrederi (on October 3, 2007):

Sorry, short description should look like this: select.short_description = 'Delete&nbsp;<input type="checkbox" id="checkboxall" name="check_all" value="Check All" />'

#

bfrederi (on January 25, 2008):

Lines 59, 66, and 71 generate this error with version .97: "global name '_' is not defined" I'm not very good with Python, so I'm not sure how to fix this. Any suggestions?

Also with my comment on using jQuery in short_description, you will have to use mark_safe() on that now, since autoescape defaults to on in .97. (from django.utils.safestring import mark_safe). Otherwise the html won't render properly.

#

bfrederi (on March 3, 2008):

I don't know python well enough to know why those lines were causing errors, but I changed it to: request.user.message_set.create(message="The %(name)s %(obj)s were deleted successfully." % {'name': opts.verbose_name_plural, 'obj': ", ".join(deleted)}) instead and it works.

#

Please login first before commenting.