Skip to content

Commit

Permalink
Fixed #29723 -- Fixed crash if InlineModelAdmin.has_add_permission() …
Browse files Browse the repository at this point in the history
…doesn't accept the obj argument.

* Refs #27991 -- Added testing for ModelAdmin.get_inline_instances() if the inline's has_add_permission() doesn't accept 'obj'.

* Fixed #29723 -- Fixed crash if InlineModelAdmin.has_add_permission() doesn't accept the obj argument.
  • Loading branch information
timgraham authored and carltongibson committed Aug 30, 2018
1 parent 54b3314 commit fd8a7a5
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 8 deletions.
16 changes: 8 additions & 8 deletions django/contrib/admin/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,13 +585,8 @@ def get_inline_instances(self, request, obj=None):
inline_instances = []
for inline_class in self.inlines:
inline = inline_class(self.model, self.admin_site)
# RemovedInDjango30Warning: obj will be a required argument.
args = get_func_args(inline.has_add_permission)
if 'obj' in args:
inline_has_add_permission = inline.has_add_permission(request, obj)
else:
inline_has_add_permission = inline.has_add_permission(request)
if request:
inline_has_add_permission = inline._has_add_permission(request, obj)
if not (inline.has_view_or_change_permission(request, obj) or
inline_has_add_permission or
inline.has_delete_permission(request, obj)):
Expand Down Expand Up @@ -1484,7 +1479,7 @@ def get_inline_formsets(self, request, formsets, inline_instances, obj=None):
for inline, formset in zip(inline_instances, formsets):
fieldsets = list(inline.get_fieldsets(request, obj))
readonly = list(inline.get_readonly_fields(request, obj))
has_add_permission = inline.has_add_permission(request, obj)
has_add_permission = inline._has_add_permission(request, obj)
has_change_permission = inline.has_change_permission(request, obj)
has_delete_permission = inline.has_delete_permission(request, obj)
has_view_permission = inline.has_view_permission(request, obj)
Expand Down Expand Up @@ -2002,6 +1997,11 @@ def media(self):
js.append('collapse%s.js' % extra)
return forms.Media(js=['admin/js/%s' % url for url in js])

def _has_add_permission(self, request, obj):
# RemovedInDjango30Warning: obj will be a required argument.
args = get_func_args(self.has_add_permission)
return self.has_add_permission(request, obj) if 'obj' in args else self.has_add_permission(request)

def get_extra(self, request, obj=None, **kwargs):
"""Hook for customizing the number of extra inline forms."""
return self.extra
Expand Down Expand Up @@ -2047,7 +2047,7 @@ def get_formset(self, request, obj=None, **kwargs):

base_model_form = defaults['form']
can_change = self.has_change_permission(request, obj) if request else True
can_add = self.has_add_permission(request, obj) if request else True
can_add = self._has_add_permission(request, obj) if request else True

class DeleteProtectedModelForm(base_model_form):

Expand Down
3 changes: 3 additions & 0 deletions docs/releases/2.1.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ Bugfixes
``values_list()`` after combining querysets with ``extra()`` with
``union()``, ``difference()``, or ``intersection()`` crashed due to
mismatching columns (:ticket:`29694`).

* Fixed crash if ``InlineModelAdmin.has_add_permission()`` doesn't accept the
``obj`` argument (:ticket:`29723`).
46 changes: 46 additions & 0 deletions tests/modeladmin/test_has_add_permission_obj_deprecation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from datetime import date

from django.contrib.admin.options import ModelAdmin, TabularInline
from django.contrib.admin.sites import AdminSite
from django.test import TestCase
from django.utils.deprecation import RemovedInDjango30Warning

from .models import Band, Song
Expand Down Expand Up @@ -56,3 +60,45 @@ class BandAdmin(ModelAdmin):
)
with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
self.assertIsValid(BandAdmin, Band)


class MockRequest:
method = 'POST'
FILES = {}
POST = {}


class SongInline(TabularInline):
model = Song

def has_add_permission(self, request):
return True


class BandAdmin(ModelAdmin):
inlines = [SongInline]


class ModelAdminTests(TestCase):

def setUp(self):
self.band = Band.objects.create(name='The Doors', bio='', sign_date=date(1965, 1, 1))
self.song = Song.objects.create(name='test', band=self.band)
self.site = AdminSite()
self.request = MockRequest()
self.request.user = self.MockAddUser()
self.ma = BandAdmin(Band, self.site)

class MockAddUser:
def has_perm(self, perm):
return perm == 'modeladmin.add_band'

def test_get_inline_instances(self):
self.assertEqual(len(self.ma.get_inline_instances(self.request)), 1)

def test_get_inline_formsets(self):
formsets, inline_instances = self.ma._create_formsets(self.request, self.band, change=True)
self.assertEqual(len(self.ma.get_inline_formsets(self.request, formsets, inline_instances)), 1)

def test_get_formsets_with_inlines(self):
self.assertEqual(len(list(self.ma. get_formsets_with_inlines(self.request, self.band))), 1)

0 comments on commit fd8a7a5

Please sign in to comment.