diff options
author | antoinehumbert <antoine.humbert@gmail.com> | 2020-08-12 21:34:20 +0200 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-09-10 10:10:53 +0200 |
commit | de95c826673be9ea519acc86fd898631d1a11356 (patch) | |
tree | 830a432cbea68a2077461a58309c802f8ff7b6bf /tests/admin_inlines | |
parent | 06e59d97a3c6e8e600ff11dadf994fae467fc785 (diff) | |
download | django-de95c826673be9ea519acc86fd898631d1a11356.tar.gz |
Fixed #31867 -- Made TabularInline handling of hidden fields with view-only permissions consistent with StackedInline.
Diffstat (limited to 'tests/admin_inlines')
-rw-r--r-- | tests/admin_inlines/admin.py | 36 | ||||
-rw-r--r-- | tests/admin_inlines/tests.py | 127 | ||||
-rw-r--r-- | tests/admin_inlines/urls.py | 3 |
3 files changed, 166 insertions, 0 deletions
diff --git a/tests/admin_inlines/admin.py b/tests/admin_inlines/admin.py index 9171c7102a..c444526241 100644 --- a/tests/admin_inlines/admin.py +++ b/tests/admin_inlines/admin.py @@ -342,6 +342,35 @@ class ClassAdminStackedVertical(admin.ModelAdmin): inlines = [ClassStackedVertical] +class ChildHiddenFieldForm(forms.ModelForm): + class Meta: + model = SomeChildModel + fields = ['name', 'position', 'parent'] + widgets = {'position': forms.HiddenInput} + + def _post_clean(self): + super()._post_clean() + if self.instance is not None and self.instance.position == 1: + self.add_error(None, ValidationError('A non-field error')) + + +class ChildHiddenFieldTabularInline(admin.TabularInline): + model = SomeChildModel + form = ChildHiddenFieldForm + + +class ChildHiddenFieldInFieldsGroupStackedInline(admin.StackedInline): + model = SomeChildModel + form = ChildHiddenFieldForm + fields = [('name', 'position')] + + +class ChildHiddenFieldOnSingleLineStackedInline(admin.StackedInline): + model = SomeChildModel + form = ChildHiddenFieldForm + fields = ('name', 'position') + + site.register(TitleCollection, inlines=[TitleInline]) # Test bug #12561 and #12778 # only ModelAdmin media @@ -373,3 +402,10 @@ site.register(Course, ClassAdminStackedHorizontal) site.register(CourseProxy, ClassAdminStackedVertical) site.register(CourseProxy1, ClassAdminTabularVertical) site.register(CourseProxy2, ClassAdminTabularHorizontal) +# Used to test hidden fields in tabular and stacked inlines. +site2 = admin.AdminSite(name='tabular_inline_hidden_field_admin') +site2.register(SomeParentModel, inlines=[ChildHiddenFieldTabularInline]) +site3 = admin.AdminSite(name='stacked_inline_hidden_field_in_group_admin') +site3.register(SomeParentModel, inlines=[ChildHiddenFieldInFieldsGroupStackedInline]) +site4 = admin.AdminSite(name='stacked_inline_hidden_field_on_single_line_admin') +site4.register(SomeParentModel, inlines=[ChildHiddenFieldOnSingleLineStackedInline]) diff --git a/tests/admin_inlines/tests.py b/tests/admin_inlines/tests.py index c96853a7ff..12f36f4483 100644 --- a/tests/admin_inlines/tests.py +++ b/tests/admin_inlines/tests.py @@ -36,6 +36,26 @@ class TestInline(TestDataMixin, TestCase): cls.holder = Holder.objects.create(dummy=13) Inner.objects.create(dummy=42, holder=cls.holder) + cls.parent = SomeParentModel.objects.create(name='a') + SomeChildModel.objects.create(name='b', position='0', parent=cls.parent) + SomeChildModel.objects.create(name='c', position='1', parent=cls.parent) + + cls.view_only_user = User.objects.create_user( + username='user', password='pwd', is_staff=True, + ) + parent_ct = ContentType.objects.get_for_model(SomeParentModel) + child_ct = ContentType.objects.get_for_model(SomeChildModel) + permission = Permission.objects.get( + codename='view_someparentmodel', + content_type=parent_ct, + ) + cls.view_only_user.user_permissions.add(permission) + permission = Permission.objects.get( + codename='view_somechildmodel', + content_type=child_ct, + ) + cls.view_only_user.user_permissions.add(permission) + def setUp(self): self.client.force_login(self.superuser) @@ -227,6 +247,113 @@ class TestInline(TestDataMixin, TestCase): response.rendered_content, ) + def test_tabular_inline_hidden_field_with_view_only_permissions(self): + """ + Content of hidden field is not visible in tabular inline when user has + view-only permission. + """ + self.client.force_login(self.view_only_user) + url = reverse( + 'tabular_inline_hidden_field_admin:admin_inlines_someparentmodel_change', + args=(self.parent.pk,), + ) + response = self.client.get(url) + self.assertInHTML('<th class="column-position hidden">Position</th>', response.rendered_content) + self.assertInHTML('<td class="field-position hidden"><p>0</p></td>', response.rendered_content) + self.assertInHTML('<td class="field-position hidden"><p>1</p></td>', response.rendered_content) + + def test_stacked_inline_hidden_field_with_view_only_permissions(self): + """ + Content of hidden field is not visible in stacked inline when user has + view-only permission. + """ + self.client.force_login(self.view_only_user) + url = reverse( + 'stacked_inline_hidden_field_in_group_admin:admin_inlines_someparentmodel_change', + args=(self.parent.pk,), + ) + response = self.client.get(url) + # The whole line containing name + position fields is not hidden. + self.assertContains(response, '<div class="form-row field-name field-position">') + # The div containing the position field is hidden. + self.assertInHTML( + '<div class="fieldBox field-position hidden">' + '<label class="inline">Position:</label>' + '<div class="readonly">0</div></div>', + response.rendered_content, + ) + self.assertInHTML( + '<div class="fieldBox field-position hidden">' + '<label class="inline">Position:</label>' + '<div class="readonly">1</div></div>', + response.rendered_content, + ) + + def test_stacked_inline_single_hidden_field_in_line_with_view_only_permissions(self): + """ + Content of hidden field is not visible in stacked inline when user has + view-only permission and the field is grouped on a separate line. + """ + self.client.force_login(self.view_only_user) + url = reverse( + 'stacked_inline_hidden_field_on_single_line_admin:admin_inlines_someparentmodel_change', + args=(self.parent.pk,), + ) + response = self.client.get(url) + # The whole line containing position field is hidden. + self.assertInHTML( + '<div class="form-row hidden field-position">' + '<div><label>Position:</label>' + '<div class="readonly">0</div></div></div>', + response.rendered_content, + ) + self.assertInHTML( + '<div class="form-row hidden field-position">' + '<div><label>Position:</label>' + '<div class="readonly">1</div></div></div>', + response.rendered_content, + ) + + def test_tabular_inline_with_hidden_field_non_field_errors_has_correct_colspan(self): + """ + In tabular inlines, when a form has non-field errors, those errors + are rendered in a table line with a single cell spanning the whole + table width. Colspan must be equal to the number of visible columns. + """ + parent = SomeParentModel.objects.create(name='a') + child = SomeChildModel.objects.create(name='b', position='0', parent=parent) + url = reverse( + 'tabular_inline_hidden_field_admin:admin_inlines_someparentmodel_change', + args=(parent.id,), + ) + data = { + 'name': parent.name, + 'somechildmodel_set-TOTAL_FORMS': 1, + 'somechildmodel_set-INITIAL_FORMS': 1, + 'somechildmodel_set-MIN_NUM_FORMS': 0, + 'somechildmodel_set-MAX_NUM_FORMS': 1000, + '_save': 'Save', + 'somechildmodel_set-0-id': child.id, + 'somechildmodel_set-0-parent': parent.id, + 'somechildmodel_set-0-name': child.name, + 'somechildmodel_set-0-position': 1, + } + response = self.client.post(url, data) + # Form has 3 visible columns and 1 hidden column. + self.assertInHTML( + '<thead><tr><th class="original"></th>' + '<th class="column-name required">Name</th>' + '<th class="column-position required hidden">Position</th>' + '<th>Delete?</th></tr></thead>', + response.rendered_content, + ) + # The non-field error must be spanned on 3 (visible) columns. + self.assertInHTML( + '<tr class="row-form-errors"><td colspan="3">' + '<ul class="errorlist nonfield"><li>A non-field error</li></ul></td></tr>', + response.rendered_content, + ) + def test_non_related_name_inline(self): """ Multiple inlines with related_name='+' have correct form prefixes. diff --git a/tests/admin_inlines/urls.py b/tests/admin_inlines/urls.py index be569cdca5..5345386917 100644 --- a/tests/admin_inlines/urls.py +++ b/tests/admin_inlines/urls.py @@ -4,4 +4,7 @@ from . import admin urlpatterns = [ path('admin/', admin.site.urls), + path('admin2/', admin.site2.urls), + path('admin3/', admin.site3.urls), + path('admin4/', admin.site4.urls), ] |