from django.contrib import admin from django.contrib.auth.models import Permission, User from django.contrib.contenttypes.models import ContentType from django.test import TestCase from .models import Band class AdminActionsTests(TestCase): @classmethod def setUpTestData(cls): cls.superuser = User.objects.create_superuser( username="super", password="secret", email="super@example.com" ) content_type = ContentType.objects.get_for_model(Band) Permission.objects.create( name="custom", codename="custom_band", content_type=content_type ) for user_type in ("view", "add", "change", "delete", "custom"): username = "%suser" % user_type user = User.objects.create_user( username=username, password="secret", is_staff=True ) permission = Permission.objects.get( codename="%s_band" % user_type, content_type=content_type ) user.user_permissions.add(permission) setattr(cls, username, user) def test_get_actions_respects_permissions(self): class MockRequest: pass class BandAdmin(admin.ModelAdmin): actions = ["custom_action"] @admin.action def custom_action(modeladmin, request, queryset): pass def has_custom_permission(self, request): return request.user.has_perm("%s.custom_band" % self.opts.app_label) ma = BandAdmin(Band, admin.AdminSite()) mock_request = MockRequest() mock_request.GET = {} cases = [ (None, self.viewuser, ["custom_action"]), ("view", self.superuser, ["delete_selected", "custom_action"]), ("view", self.viewuser, ["custom_action"]), ("add", self.adduser, ["custom_action"]), ("change", self.changeuser, ["custom_action"]), ("delete", self.deleteuser, ["delete_selected", "custom_action"]), ("custom", self.customuser, ["custom_action"]), ] for permission, user, expected in cases: with self.subTest(permission=permission, user=user): if permission is None: if hasattr(BandAdmin.custom_action, "allowed_permissions"): del BandAdmin.custom_action.allowed_permissions else: BandAdmin.custom_action.allowed_permissions = (permission,) 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"] @admin.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"]) def test_global_actions_description(self): @admin.action(description="Site-wide admin action 1.") def global_action_1(modeladmin, request, queryset): pass @admin.action def global_action_2(modeladmin, request, queryset): pass admin_site = admin.AdminSite() admin_site.add_action(global_action_1) admin_site.add_action(global_action_2) class BandAdmin(admin.ModelAdmin): pass ma = BandAdmin(Band, admin_site) self.assertEqual( [description for _, _, description in ma._get_base_actions()], [ "Delete selected %(verbose_name_plural)s", "Site-wide admin action 1.", "Global action 2", ], ) def test_actions_replace_global_action(self): @admin.action(description="Site-wide admin action 1.") def global_action_1(modeladmin, request, queryset): pass @admin.action(description="Site-wide admin action 2.") def global_action_2(modeladmin, request, queryset): pass admin.site.add_action(global_action_1, name="custom_action_1") admin.site.add_action(global_action_2, name="custom_action_2") @admin.action(description="Local admin action 1.") def custom_action_1(modeladmin, request, queryset): pass class BandAdmin(admin.ModelAdmin): actions = [custom_action_1, "custom_action_2"] @admin.action(description="Local admin action 2.") def custom_action_2(self, request, queryset): pass ma = BandAdmin(Band, admin.site) self.assertEqual(ma.check(), []) self.assertEqual( [ desc for _, name, desc in ma._get_base_actions() if name.startswith("custom_action") ], [ "Local admin action 1.", "Local admin action 2.", ], )