diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 0d10d29a04..eb2c8cd094 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -2126,7 +2126,8 @@ class InlineModelAdmin(BaseModelAdmin): queryset = queryset.none() return queryset - def has_add_permission(self, request, obj): + def has_add_permission(self, request, obj=None): + # RemovedInDjango31Warning: obj becomes a mandatory argument. if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 7a14d694a6..c163dc9f2e 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -2413,7 +2413,9 @@ The ``InlineModelAdmin`` class adds or customizes: .. versionchanged:: 2.1 - The ``obj`` argument was added. + The ``obj`` argument was added. During the deprecation period, it may + also be ``None`` if third-party calls to ``has_add_permission()`` don't + provide it. .. method:: InlineModelAdmin.has_change_permission(request, obj=None) diff --git a/docs/releases/2.1.6.txt b/docs/releases/2.1.6.txt index 894eb160b2..d5f342f546 100644 --- a/docs/releases/2.1.6.txt +++ b/docs/releases/2.1.6.txt @@ -9,4 +9,6 @@ Django 2.1.6 several bugs in 2.1.5. Bugfixes ======== -* ... +* Made the ``obj`` argument of ``InlineModelAdmin.has_add_permission()`` + optional to restore backwards compatibility with third-party code that + doesn't provide it (:ticket:`30097`). diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py index 6934bf2b3c..0d78dd9c21 100644 --- a/tests/modeladmin/tests.py +++ b/tests/modeladmin/tests.py @@ -734,6 +734,10 @@ class ModelAdminPermissionTests(SimpleTestCase): def has_perm(self, perm): return perm == 'modeladmin.add_band' + class MockAddUserWithInline(MockUser): + def has_perm(self, perm): + return perm == 'modeladmin.add_concert' + class MockChangeUser(MockUser): def has_perm(self, perm): return perm == 'modeladmin.change_band' @@ -793,6 +797,26 @@ class ModelAdminPermissionTests(SimpleTestCase): self.assertEqual(len(inline_instances), 1) self.assertIsInstance(inline_instances[0], ConcertInline) + def test_inline_has_add_permission_without_obj(self): + # This test will be removed in Django 3.1 when `obj` becomes a required + # argument of has_add_permission() (#27991). + class ConcertInline(TabularInline): + model = Concert + + def has_add_permission(self, request): + return super().has_add_permission(request) + + class BandAdmin(ModelAdmin): + inlines = [ConcertInline] + + ma = BandAdmin(Band, AdminSite()) + request = MockRequest() + request.user = self.MockAddUserWithInline() + band = Band(name='The Doors', bio='', sign_date=date(1965, 1, 1)) + inline_instances = ma.get_inline_instances(request, band) + self.assertEqual(len(inline_instances), 1) + self.assertIsInstance(inline_instances[0], ConcertInline) + def test_has_change_permission(self): """ has_change_permission returns True for users who can edit objects and