summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasilis Aggelou <dimitrovasilis@hotmail.com>2017-09-04 12:24:34 +0300
committerTim Graham <timograham@gmail.com>2018-01-05 18:28:45 -0500
commit777f216d555496798a1e65fd899b0f8a0349aeca (patch)
treec7019a417caf39f4d7a9acfd6b7629029befa3cc
parentec2ce4517ac89f6c6334fe5322d1fc2007dfcbd4 (diff)
Fixed #15522 -- Added ModelAdmin.delete_queryset() to customize "delete selected objects" deletion.
-rw-r--r--django/contrib/admin/actions.py2
-rw-r--r--django/contrib/admin/options.py4
-rw-r--r--docs/ref/contrib/admin/actions.txt5
-rw-r--r--docs/ref/contrib/admin/index.txt9
-rw-r--r--docs/releases/2.1.txt3
-rw-r--r--tests/admin_views/admin.py4
-rw-r--r--tests/admin_views/test_actions.py14
7 files changed, 38 insertions, 3 deletions
diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py
index 34e809bebc..49f969f668 100644
--- a/django/contrib/admin/actions.py
+++ b/django/contrib/admin/actions.py
@@ -45,7 +45,7 @@ def delete_selected(modeladmin, request, queryset):
for obj in queryset:
obj_display = str(obj)
modeladmin.log_deletion(request, obj, obj_display)
- queryset.delete()
+ modeladmin.delete_queryset(request, queryset)
modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % {
"count": n, "items": model_ngettext(modeladmin.opts, n)
}, messages.SUCCESS)
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index d37615b1e5..090a9f6bc6 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -1043,6 +1043,10 @@ class ModelAdmin(BaseModelAdmin):
"""
obj.delete()
+ def delete_queryset(self, request, queryset):
+ """Given a queryset, delete it from the database."""
+ queryset.delete()
+
def save_formset(self, request, form, formset, change):
"""
Given an inline formset save it to the database.
diff --git a/docs/ref/contrib/admin/actions.txt b/docs/ref/contrib/admin/actions.txt
index c6f210b1de..c23c647a72 100644
--- a/docs/ref/contrib/admin/actions.txt
+++ b/docs/ref/contrib/admin/actions.txt
@@ -27,8 +27,9 @@ models. For example, here's the user module from Django's built-in
has an important caveat: your model's ``delete()`` method will not be
called.
- If you wish to override this behavior, simply write a custom action which
- accomplishes deletion in your preferred manner -- for example, by calling
+ If you wish to override this behavior, you can override
+ :meth:`.ModelAdmin.delete_queryset` or write a custom action which does
+ deletion in your preferred manner -- for example, by calling
``Model.delete()`` for each of the selected items.
For more background on bulk deletion, see the documentation on :ref:`object
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 1f7b7f152e..7622477036 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -1391,6 +1391,15 @@ templates used by the :class:`ModelAdmin` views:
operations. Call ``super().delete_model()`` to delete the object using
:meth:`.Model.delete`.
+.. method:: ModelAdmin.delete_queryset(request, queryset)
+
+ .. versionadded:: 2.1
+
+ The ``delete_queryset()`` method is given the ``HttpRequest`` and a
+ ``QuerySet`` of objects to be deleted. Override this method to customize
+ the deletion process for the "delete selected objects" :doc:`action
+ <actions>`.
+
.. method:: ModelAdmin.save_formset(request, form, formset, change)
The ``save_formset`` method is given the ``HttpRequest``, the parent
diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt
index f349d1ed9a..4d86380102 100644
--- a/docs/releases/2.1.txt
+++ b/docs/releases/2.1.txt
@@ -37,6 +37,9 @@ Minor features
* jQuery is upgraded from version 2.2.3 to 3.2.1.
+* The new :meth:`.ModelAdmin.delete_queryset` method allows customizing the
+ deletion process of the "delete selected objects" action.
+
:mod:`django.contrib.admindocs`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 12087865b4..3cfefb74e4 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -232,6 +232,10 @@ class SubscriberAdmin(admin.ModelAdmin):
actions = ['mail_admin']
action_form = MediaActionForm
+ def delete_queryset(self, request, queryset):
+ SubscriberAdmin.overridden = True
+ super().delete_queryset(request, queryset)
+
def mail_admin(self, request, selected):
EmailMessage(
'Greetings from a ModelAdmin action',
diff --git a/tests/admin_views/test_actions.py b/tests/admin_views/test_actions.py
index 453de691ce..b77714b32d 100644
--- a/tests/admin_views/test_actions.py
+++ b/tests/admin_views/test_actions.py
@@ -9,6 +9,7 @@ from django.template.response import TemplateResponse
from django.test import TestCase, override_settings
from django.urls import reverse
+from .admin import SubscriberAdmin
from .forms import MediaActionForm
from .models import (
Actor, Answer, ExternalSubscriber, Question, Subscriber,
@@ -128,6 +129,19 @@ class AdminActionsTest(TestCase):
# The page doesn't display a link to the nonexistent change page.
self.assertContains(response, '<li>Unchangeable object: %s</li>' % obj, 1, html=True)
+ def test_delete_queryset_hook(self):
+ delete_confirmation_data = {
+ ACTION_CHECKBOX_NAME: [self.s1.pk, self.s2.pk],
+ 'action': 'delete_selected',
+ 'post': 'yes',
+ 'index': 0,
+ }
+ SubscriberAdmin.overridden = False
+ self.client.post(reverse('admin:admin_views_subscriber_changelist'), delete_confirmation_data)
+ # SubscriberAdmin.delete_queryset() sets overridden to True.
+ self.assertIs(SubscriberAdmin.overridden, True)
+ self.assertEqual(Subscriber.objects.all().count(), 0)
+
def test_custom_function_mail_action(self):
"""A custom action may be defined in a function."""
action_data = {