Fixed #29917 -- Stopped collecting ModelAdmin.actions from base ModelAdmins.

This commit is contained in:
Matthias Kestenholz 2018-11-10 00:52:30 +01:00 committed by Tim Graham
parent a375e911ef
commit f9ff1df1da
4 changed files with 46 additions and 11 deletions

View File

@ -859,13 +859,8 @@ class ModelAdmin(BaseModelAdmin):
for (name, func) in self.admin_site.actions:
description = getattr(func, 'short_description', name.replace('_', ' '))
actions.append((func, name, description))
# Then gather them from the model admin and all parent classes,
# starting with self and working back up.
for klass in self.__class__.mro()[::-1]:
class_actions = getattr(klass, 'actions', []) or []
actions.extend(self.get_action(action) for action in class_actions)
# Add actions from this ModelAdmin.
actions.extend(self.get_action(action) for action in self.actions or [])
# get_action might have returned None, so filter any of those out.
return filter(None, actions)

View File

@ -343,10 +343,8 @@ Conditionally enabling or disabling actions
This returns a dictionary of actions allowed. The keys are action names, and
the values are ``(function, name, short_description)`` tuples.
Most of the time you'll use this method to conditionally remove actions from
the list gathered by the superclass. For example, if I only wanted users
whose names begin with 'J' to be able to delete objects in bulk, I could do
the following::
For example, if you only want users whose names begin with 'J' to be able
to delete objects in bulk::
class MyModelAdmin(admin.ModelAdmin):
...

View File

@ -293,6 +293,27 @@ Database backend API
* Third party database backends must implement support for partial indexes or
set ``DatabaseFeatures.supports_partial_indexes`` to ``False``.
Admin actions are no longer collected from base ``ModelAdmin`` classes
----------------------------------------------------------------------
For example, in older versions of Django::
from django.contrib import admin
class BaseAdmin(admin.ModelAdmin):
actions = ['a']
class SubAdmin(BaseAdmin):
actions = ['b']
``SubAdmin`` will have actions ``'a'`` and ``'b'``.
Now ``actions`` follows standard Python inheritance. To get the same result as
before::
class SubAdmin(BaseAdmin):
actions = BaseAdmin.actions + ['b']
:mod:`django.contrib.gis`
-------------------------

View File

@ -55,3 +55,24 @@ class AdminActionsTests(TestCase):
mock_request.user = user
actions = ma.get_actions(mock_request)
self.assertEqual(list(actions.keys()), expected)
def test_actions_inheritance(self):
class AdminBase(admin.ModelAdmin):
actions = ['custom_action']
def custom_action(modeladmin, request, queryset):
pass
class AdminA(AdminBase):
pass
class AdminB(AdminBase):
actions = None
ma1 = AdminA(Band, admin.AdminSite())
action_names = [name for _, name, _ in ma1._get_base_actions()]
self.assertEqual(action_names, ['delete_selected', 'custom_action'])
# `actions = None` removes actions from superclasses.
ma2 = AdminB(Band, admin.AdminSite())
action_names = [name for _, name, _ in ma2._get_base_actions()]
self.assertEqual(action_names, ['delete_selected'])