mirror of https://github.com/django/django.git
Fixed #23869 -- Made ModelAdmin.get_deleted_objects() use has_delete_permission() for permissions checking.
This commit is contained in:
parent
ec2c9c3531
commit
3eb9127678
1
AUTHORS
1
AUTHORS
|
@ -590,6 +590,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Mikhail Korobov <kmike84@googlemail.com>
|
Mikhail Korobov <kmike84@googlemail.com>
|
||||||
Mikko Hellsing <mikko@sorl.net>
|
Mikko Hellsing <mikko@sorl.net>
|
||||||
Mikołaj Siedlarek <mikolaj.siedlarek@gmail.com>
|
Mikołaj Siedlarek <mikolaj.siedlarek@gmail.com>
|
||||||
|
milkomeda
|
||||||
Milton Waddams
|
Milton Waddams
|
||||||
mitakummaa@gmail.com
|
mitakummaa@gmail.com
|
||||||
mmarshall
|
mmarshall
|
||||||
|
|
|
@ -1812,7 +1812,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
Hook for customizing the delete process for the delete view and the
|
Hook for customizing the delete process for the delete view and the
|
||||||
"delete selected" action.
|
"delete selected" action.
|
||||||
"""
|
"""
|
||||||
return get_deleted_objects(objs, request.user, self.admin_site)
|
return get_deleted_objects(objs, request, self.admin_site)
|
||||||
|
|
||||||
@csrf_protect_m
|
@csrf_protect_m
|
||||||
def delete_view(self, request, object_id, extra_context=None):
|
def delete_view(self, request, object_id, extra_context=None):
|
||||||
|
|
|
@ -2,7 +2,6 @@ import datetime
|
||||||
import decimal
|
import decimal
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.contrib.auth import get_permission_codename
|
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db import models, router
|
from django.db import models, router
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
|
@ -117,7 +116,7 @@ def flatten_fieldsets(fieldsets):
|
||||||
return field_names
|
return field_names
|
||||||
|
|
||||||
|
|
||||||
def get_deleted_objects(objs, user, admin_site):
|
def get_deleted_objects(objs, request, admin_site):
|
||||||
"""
|
"""
|
||||||
Find all objects related to ``objs`` that should also be deleted. ``objs``
|
Find all objects related to ``objs`` that should also be deleted. ``objs``
|
||||||
must be a homogeneous iterable of objects (e.g. a QuerySet).
|
must be a homogeneous iterable of objects (e.g. a QuerySet).
|
||||||
|
@ -136,12 +135,15 @@ def get_deleted_objects(objs, user, admin_site):
|
||||||
perms_needed = set()
|
perms_needed = set()
|
||||||
|
|
||||||
def format_callback(obj):
|
def format_callback(obj):
|
||||||
has_admin = obj.__class__ in admin_site._registry
|
model = obj.__class__
|
||||||
|
has_admin = model in admin_site._registry
|
||||||
opts = obj._meta
|
opts = obj._meta
|
||||||
|
|
||||||
no_edit_link = '%s: %s' % (capfirst(opts.verbose_name), obj)
|
no_edit_link = '%s: %s' % (capfirst(opts.verbose_name), obj)
|
||||||
|
|
||||||
if has_admin:
|
if has_admin:
|
||||||
|
if not admin_site._registry[model].has_delete_permission(request, obj):
|
||||||
|
perms_needed.add(opts.verbose_name)
|
||||||
try:
|
try:
|
||||||
admin_url = reverse('%s:%s_%s_change'
|
admin_url = reverse('%s:%s_%s_change'
|
||||||
% (admin_site.name,
|
% (admin_site.name,
|
||||||
|
@ -152,10 +154,6 @@ def get_deleted_objects(objs, user, admin_site):
|
||||||
# Change url doesn't exist -- don't display link to edit
|
# Change url doesn't exist -- don't display link to edit
|
||||||
return no_edit_link
|
return no_edit_link
|
||||||
|
|
||||||
if 'delete' in opts.default_permissions:
|
|
||||||
p = '%s.%s' % (opts.app_label, get_permission_codename('delete', opts))
|
|
||||||
if not user.has_perm(p):
|
|
||||||
perms_needed.add(opts.verbose_name)
|
|
||||||
# Display a link to the admin page.
|
# Display a link to the admin page.
|
||||||
return format_html('{}: <a href="{}">{}</a>',
|
return format_html('{}: <a href="{}">{}</a>',
|
||||||
capfirst(opts.verbose_name),
|
capfirst(opts.verbose_name),
|
||||||
|
|
|
@ -669,13 +669,34 @@ class ModelAdminTests(TestCase):
|
||||||
def test_get_deleted_objects(self):
|
def test_get_deleted_objects(self):
|
||||||
mock_request = MockRequest()
|
mock_request = MockRequest()
|
||||||
mock_request.user = User.objects.create_superuser(username='bob', email='bob@test.com', password='test')
|
mock_request.user = User.objects.create_superuser(username='bob', email='bob@test.com', password='test')
|
||||||
ma = ModelAdmin(Band, self.site)
|
self.site.register(Band, ModelAdmin)
|
||||||
|
ma = self.site._registry[Band]
|
||||||
deletable_objects, model_count, perms_needed, protected = ma.get_deleted_objects([self.band], request)
|
deletable_objects, model_count, perms_needed, protected = ma.get_deleted_objects([self.band], request)
|
||||||
self.assertEqual(deletable_objects, ['Band: The Doors'])
|
self.assertEqual(deletable_objects, ['Band: The Doors'])
|
||||||
self.assertEqual(model_count, {'bands': 1})
|
self.assertEqual(model_count, {'bands': 1})
|
||||||
self.assertEqual(perms_needed, set())
|
self.assertEqual(perms_needed, set())
|
||||||
self.assertEqual(protected, [])
|
self.assertEqual(protected, [])
|
||||||
|
|
||||||
|
def test_get_deleted_objects_with_custom_has_delete_permission(self):
|
||||||
|
"""
|
||||||
|
ModelAdmin.get_deleted_objects() uses ModelAdmin.has_delete_permission()
|
||||||
|
for permissions checking.
|
||||||
|
"""
|
||||||
|
mock_request = MockRequest()
|
||||||
|
mock_request.user = User.objects.create_superuser(username='bob', email='bob@test.com', password='test')
|
||||||
|
|
||||||
|
class TestModelAdmin(ModelAdmin):
|
||||||
|
def has_delete_permission(self, request, obj=None):
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.site.register(Band, TestModelAdmin)
|
||||||
|
ma = self.site._registry[Band]
|
||||||
|
deletable_objects, model_count, perms_needed, protected = ma.get_deleted_objects([self.band], request)
|
||||||
|
self.assertEqual(deletable_objects, ['Band: The Doors'])
|
||||||
|
self.assertEqual(model_count, {'bands': 1})
|
||||||
|
self.assertEqual(perms_needed, {'band'})
|
||||||
|
self.assertEqual(protected, [])
|
||||||
|
|
||||||
|
|
||||||
class ModelAdminPermissionTests(SimpleTestCase):
|
class ModelAdminPermissionTests(SimpleTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue