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: for (name, func) in self.admin_site.actions:
description = getattr(func, 'short_description', name.replace('_', ' ')) description = getattr(func, 'short_description', name.replace('_', ' '))
actions.append((func, name, description)) actions.append((func, name, description))
# Add actions from this ModelAdmin.
# Then gather them from the model admin and all parent classes, actions.extend(self.get_action(action) for action in self.actions or [])
# 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)
# get_action might have returned None, so filter any of those out. # get_action might have returned None, so filter any of those out.
return filter(None, actions) 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 This returns a dictionary of actions allowed. The keys are action names, and
the values are ``(function, name, short_description)`` tuples. the values are ``(function, name, short_description)`` tuples.
Most of the time you'll use this method to conditionally remove actions from For example, if you only want users whose names begin with 'J' to be able
the list gathered by the superclass. For example, if I only wanted users to delete objects in bulk::
whose names begin with 'J' to be able to delete objects in bulk, I could do
the following::
class MyModelAdmin(admin.ModelAdmin): class MyModelAdmin(admin.ModelAdmin):
... ...

View File

@ -293,6 +293,27 @@ Database backend API
* Third party database backends must implement support for partial indexes or * Third party database backends must implement support for partial indexes or
set ``DatabaseFeatures.supports_partial_indexes`` to ``False``. 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` :mod:`django.contrib.gis`
------------------------- -------------------------

View File

@ -55,3 +55,24 @@ class AdminActionsTests(TestCase):
mock_request.user = user mock_request.user = user
actions = ma.get_actions(mock_request) actions = ma.get_actions(mock_request)
self.assertEqual(list(actions.keys()), expected) 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'])