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.', ], )