summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2018-12-27 20:49:02 -0500
committerTim Graham <timograham@gmail.com>2019-01-17 11:14:07 -0500
commit6079ed82f43d8cc4b2c07eb36bc14efa0a1a5c17 (patch)
tree7f8d73ef5251ca5327d695596902b79b674083c2
parent92d4d0859a63347de6e2a7bc3ddd49979cc192c5 (diff)
Refs #27991 -- Made obj a required argument of InlineModelAdmin.has_add_permission().
Per deprecation timeline.
-rw-r--r--django/contrib/admin/checks.py18
-rw-r--r--django/contrib/admin/options.py18
-rw-r--r--tests/modeladmin/test_has_add_permission_obj_deprecation.py111
-rw-r--r--tests/modeladmin/tests.py24
4 files changed, 5 insertions, 166 deletions
diff --git a/django/contrib/admin/checks.py b/django/contrib/admin/checks.py
index 3f8abdd476..a5bcc3f6df 100644
--- a/django/contrib/admin/checks.py
+++ b/django/contrib/admin/checks.py
@@ -1,4 +1,3 @@
-import warnings
from itertools import chain
from django.apps import apps
@@ -16,8 +15,6 @@ from django.forms.models import (
)
from django.template import engines
from django.template.backends.django import DjangoTemplates
-from django.utils.deprecation import RemovedInDjango30Warning
-from django.utils.inspect import get_func_args
def _issubclass(cls, classinfo):
@@ -981,7 +978,6 @@ class ModelAdminChecks(BaseModelAdminChecks):
class InlineModelAdminChecks(BaseModelAdminChecks):
def check(self, inline_obj, **kwargs):
- self._check_has_add_permission(inline_obj)
parent_model = inline_obj.parent_model
return [
*super().check(inline_obj),
@@ -1066,20 +1062,6 @@ class InlineModelAdminChecks(BaseModelAdminChecks):
else:
return []
- def _check_has_add_permission(self, obj):
- cls = obj.__class__
- try:
- func = cls.has_add_permission
- except AttributeError:
- pass
- else:
- args = get_func_args(func)
- if 'obj' not in args:
- warnings.warn(
- "Update %s.has_add_permission() to accept a positional "
- "`obj` argument." % cls.__name__, RemovedInDjango30Warning
- )
-
def must_be(type, option, obj, id):
return [
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index eb2c8cd094..ab4aa6d93b 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -45,7 +45,6 @@ from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.html import format_html
from django.utils.http import urlencode
-from django.utils.inspect import get_func_args
from django.utils.safestring import mark_safe
from django.utils.text import capfirst, format_lazy, get_text_list
from django.utils.translation import gettext as _, ngettext
@@ -587,12 +586,11 @@ class ModelAdmin(BaseModelAdmin):
for inline_class in self.inlines:
inline = inline_class(self.model, self.admin_site)
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_add_permission(request, obj) or
inline.has_delete_permission(request, obj)):
continue
- if not inline_has_add_permission:
+ if not inline.has_add_permission(request, obj):
inline.max_num = 0
inline_instances.append(inline)
@@ -1475,7 +1473,7 @@ class ModelAdmin(BaseModelAdmin):
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)
@@ -2011,11 +2009,6 @@ class InlineModelAdmin(BaseModelAdmin):
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
@@ -2061,7 +2054,7 @@ class InlineModelAdmin(BaseModelAdmin):
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):
@@ -2126,8 +2119,7 @@ class InlineModelAdmin(BaseModelAdmin):
queryset = queryset.none()
return queryset
- def has_add_permission(self, request, obj=None):
- # RemovedInDjango31Warning: obj becomes a mandatory argument.
+ def has_add_permission(self, request, obj):
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/tests/modeladmin/test_has_add_permission_obj_deprecation.py b/tests/modeladmin/test_has_add_permission_obj_deprecation.py
deleted file mode 100644
index 8e932ec7e8..0000000000
--- a/tests/modeladmin/test_has_add_permission_obj_deprecation.py
+++ /dev/null
@@ -1,111 +0,0 @@
-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
-from .test_checks import CheckTestCase
-
-
-class HasAddPermissionObjTests(CheckTestCase):
- def test_model_admin_inherited_valid(self):
- class BandAdmin(ModelAdmin):
- pass
-
- self.assertIsValid(BandAdmin, Band)
-
- def test_model_admin_valid(self):
- class BandAdmin(ModelAdmin):
- def has_add_permission(self, request):
- return super().has_add_permission(request)
-
- self.assertIsValid(BandAdmin, Band)
-
- def test_inline_admin_inherited_valid(self):
- class SongInlineAdmin(TabularInline):
- model = Song
-
- class BandAdmin(ModelAdmin):
- inlines = [SongInlineAdmin]
-
- self.assertIsValid(BandAdmin, Band)
-
- def test_inline_admin_valid(self):
- class SongInlineAdmin(TabularInline):
- model = Song
-
- def has_add_permission(self, request, obj):
- return super().has_add_permission(request, obj)
-
- class BandAdmin(ModelAdmin):
- inlines = [SongInlineAdmin]
-
- self.assertIsValid(BandAdmin, Band)
-
- def test_inline_admin_warning(self):
- class SongInlineAdmin(TabularInline):
- model = Song
-
- def has_add_permission(self, request):
- return super().has_add_permission(request)
-
- class BandAdmin(ModelAdmin):
- inlines = [SongInlineAdmin]
-
- msg = (
- "Update SongInlineAdmin.has_add_permission() to accept a "
- "positional `obj` argument."
- )
- 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):
-
- @classmethod
- def setUpTestData(cls):
- cls.band = Band.objects.create(name='The Doors', bio='', sign_date=date(1965, 1, 1))
- cls.song = Song.objects.create(name='test', band=cls.band)
-
- def setUp(self):
- self.site = AdminSite()
- self.request = MockRequest()
- self.request.POST = {
- 'song_set-TOTAL_FORMS': 4,
- 'song_set-INITIAL_FORMS': 1,
- }
- 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)
diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py
index 0d78dd9c21..6934bf2b3c 100644
--- a/tests/modeladmin/tests.py
+++ b/tests/modeladmin/tests.py
@@ -734,10 +734,6 @@ 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'
@@ -797,26 +793,6 @@ 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