mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #29917 -- Stopped collecting ModelAdmin.actions from base ModelAdmins.
This commit is contained in:
parent
a375e911ef
commit
f9ff1df1da
@ -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)
|
||||
|
||||
|
@ -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):
|
||||
...
|
||||
|
@ -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`
|
||||
-------------------------
|
||||
|
||||
|
@ -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'])
|
||||
|
Loading…
Reference in New Issue
Block a user