Adding related objects in the admin (via popup) respects user
permissions. Patch from SmileyChris. Fixed #1035. git-svn-id: http://code.djangoproject.com/svn/django/trunk@13708 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
92b91d6e7b
commit
30610719d5
|
@ -107,7 +107,13 @@ class BaseModelAdmin(object):
|
||||||
# rendered output. formfield can be None if it came from a
|
# rendered output. formfield can be None if it came from a
|
||||||
# OneToOneField with parent_link=True or a M2M intermediary.
|
# OneToOneField with parent_link=True or a M2M intermediary.
|
||||||
if formfield and db_field.name not in self.raw_id_fields:
|
if formfield and db_field.name not in self.raw_id_fields:
|
||||||
formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)
|
related_modeladmin = self.admin_site._registry.get(
|
||||||
|
db_field.rel.to)
|
||||||
|
can_add_related = bool(related_modeladmin and
|
||||||
|
related_modeladmin.has_add_permission(request))
|
||||||
|
formfield.widget = widgets.RelatedFieldWidgetWrapper(
|
||||||
|
formfield.widget, db_field.rel, self.admin_site,
|
||||||
|
can_add_related=can_add_related)
|
||||||
|
|
||||||
return formfield
|
return formfield
|
||||||
|
|
||||||
|
|
|
@ -205,13 +205,18 @@ class RelatedFieldWidgetWrapper(forms.Widget):
|
||||||
This class is a wrapper to a given widget to add the add icon for the
|
This class is a wrapper to a given widget to add the add icon for the
|
||||||
admin interface.
|
admin interface.
|
||||||
"""
|
"""
|
||||||
def __init__(self, widget, rel, admin_site):
|
def __init__(self, widget, rel, admin_site, can_add_related=None):
|
||||||
self.is_hidden = widget.is_hidden
|
self.is_hidden = widget.is_hidden
|
||||||
self.needs_multipart_form = widget.needs_multipart_form
|
self.needs_multipart_form = widget.needs_multipart_form
|
||||||
self.attrs = widget.attrs
|
self.attrs = widget.attrs
|
||||||
self.choices = widget.choices
|
self.choices = widget.choices
|
||||||
self.widget = widget
|
self.widget = widget
|
||||||
self.rel = rel
|
self.rel = rel
|
||||||
|
# Backwards compatible check for whether a user can add related
|
||||||
|
# objects.
|
||||||
|
if can_add_related is None:
|
||||||
|
can_add_related = rel_to in self.admin_site._registry
|
||||||
|
self.can_add_related = can_add_related
|
||||||
# so we can check if the related object is registered with this AdminSite
|
# so we can check if the related object is registered with this AdminSite
|
||||||
self.admin_site = admin_site
|
self.admin_site = admin_site
|
||||||
|
|
||||||
|
@ -236,7 +241,7 @@ class RelatedFieldWidgetWrapper(forms.Widget):
|
||||||
related_url = '%s%s/%s/add/' % info
|
related_url = '%s%s/%s/add/' % info
|
||||||
self.widget.choices = self.choices
|
self.widget.choices = self.choices
|
||||||
output = [self.widget.render(name, value, *args, **kwargs)]
|
output = [self.widget.render(name, value, *args, **kwargs)]
|
||||||
if rel_to in self.admin_site._registry: # If the related object has an admin interface:
|
if self.can_add_related:
|
||||||
# TODO: "id_" is hard-coded here. This should instead use the correct
|
# TODO: "id_" is hard-coded here. This should instead use the correct
|
||||||
# API to determine the ID dynamically.
|
# API to determine the ID dynamically.
|
||||||
output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
|
output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
|
||||||
|
|
|
@ -604,6 +604,28 @@ class AdminViewPermissionsTest(TestCase):
|
||||||
'Plural error message not found in response to post with multiple errors.')
|
'Plural error message not found in response to post with multiple errors.')
|
||||||
self.client.get('/test_admin/admin/logout/')
|
self.client.get('/test_admin/admin/logout/')
|
||||||
|
|
||||||
|
def testConditionallyShowAddSectionLink(self):
|
||||||
|
"""
|
||||||
|
The foreign key widget should only show the "add related" button if the
|
||||||
|
user has permission to add that related item.
|
||||||
|
"""
|
||||||
|
# Set up and log in user.
|
||||||
|
url = '/test_admin/admin/admin_views/article/add/'
|
||||||
|
add_link_text = ' class="add-another"'
|
||||||
|
self.client.get('/test_admin/admin/')
|
||||||
|
self.client.post('/test_admin/admin/', self.adduser_login)
|
||||||
|
# The add user can't add sections yet, so they shouldn't see the "add
|
||||||
|
# section" link.
|
||||||
|
response = self.client.get(url)
|
||||||
|
self.assertNotContains(response, add_link_text)
|
||||||
|
# Allow the add user to add sections too. Now they can see the "add
|
||||||
|
# section" link.
|
||||||
|
add_user = User.objects.get(username='adduser')
|
||||||
|
perm = get_perm(Section, Section._meta.get_add_permission())
|
||||||
|
add_user.user_permissions.add(perm)
|
||||||
|
response = self.client.get(url)
|
||||||
|
self.assertContains(response, add_link_text)
|
||||||
|
|
||||||
def testCustomModelAdminTemplates(self):
|
def testCustomModelAdminTemplates(self):
|
||||||
self.client.get('/test_admin/admin/')
|
self.client.get('/test_admin/admin/')
|
||||||
self.client.post('/test_admin/admin/', self.super_login)
|
self.client.post('/test_admin/admin/', self.super_login)
|
||||||
|
|
Loading…
Reference in New Issue