Skip to content

Commit

Permalink
Fixed #29917 -- Stopped collecting ModelAdmin.actions from base Model…
Browse files Browse the repository at this point in the history
…Admins.
  • Loading branch information
matthiask authored and timgraham committed Nov 9, 2018
1 parent a375e91 commit f9ff1df
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 11 deletions.
9 changes: 2 additions & 7 deletions django/contrib/admin/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,13 +859,8 @@ def _get_base_actions(self):
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)

Expand Down
6 changes: 2 additions & 4 deletions docs/ref/contrib/admin/actions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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):
...
Expand Down
21 changes: 21 additions & 0 deletions docs/releases/2.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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`
-------------------------

Expand Down
21 changes: 21 additions & 0 deletions tests/modeladmin/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,24 @@ def has_custom_permission(self, request):
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'])

0 comments on commit f9ff1df

Please sign in to comment.