diff options
| author | Matthias Kestenholz <mk@feinheit.ch> | 2025-01-15 21:04:26 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-15 17:04:26 -0300 |
| commit | 6a7ee02f5994c65bbefe92a3da74f22326970cf9 (patch) | |
| tree | d49780a99dbb0ad8b85522b55dcaf54fafde0264 /tests/forms_tests | |
| parent | 0cabed9efa2c7abd1693860069f20ec5db41fcd8 (diff) | |
Fixed #35521 -- Allowed overriding BoundField class on fields, forms and renderers.
Thank you Sarah Boyce, Carlton Gibson, Tim Schilling and Adam Johnson
for reviews.
Co-authored-by: Christophe Henry <contact@c-henry.fr>
Co-authored-by: David Smith <smithdc@gmail.com>
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Co-authored-by: Matthias Kestenholz <mk@feinheit.ch>
Diffstat (limited to 'tests/forms_tests')
| -rw-r--r-- | tests/forms_tests/tests/test_forms.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py index b41424d43d..20c86754c6 100644 --- a/tests/forms_tests/tests/test_forms.py +++ b/tests/forms_tests/tests/test_forms.py @@ -8,6 +8,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile from django.core.validators import MaxValueValidator, RegexValidator from django.forms import ( BooleanField, + BoundField, CharField, CheckboxSelectMultiple, ChoiceField, @@ -4971,6 +4972,22 @@ class RendererTests(SimpleTestCase): context = form.get_context() self.assertEqual(context["errors"].renderer, custom) + def test_boundfield_fallback(self): + class RendererWithoutBoundFieldClassAttribute: + form_template_name = "django/forms/div.html" + formset_template_name = "django/forms/formsets/div.html" + field_template_name = "django/forms/field.html" + + def render(self, template_name, context, request=None): + return "Nice" + + class UserForm(Form): + name = CharField() + + form = UserForm(renderer=RendererWithoutBoundFieldClassAttribute()) + self.assertIsInstance(form["name"], BoundField) + self.assertEqual(form["name"].as_field_group(), "Nice") + class TemplateTests(SimpleTestCase): def test_iterate_radios(self): @@ -5473,3 +5490,146 @@ class OverrideTests(SimpleTestCase): '<label for="id_name" class="required">Name:</label>' '<legend class="required">Language:</legend>', ) + + +class BoundFieldWithoutColon(BoundField): + def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None): + return super().label_tag( + contents=contents, attrs=attrs, label_suffix="", tag=None + ) + + +class BoundFieldWithTwoColons(BoundField): + def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None): + return super().label_tag( + contents=contents, attrs=attrs, label_suffix="::", tag=None + ) + + +class BoundFieldWithCustomClass(BoundField): + def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None): + attrs = attrs or {} + attrs["class"] = "custom-class" + return super().label_tag(contents, attrs, label_suffix, tag) + + +class BoundFieldWithWrappingClass(BoundField): + def css_classes(self, extra_classes=None): + parent_classes = super().css_classes(extra_classes) + return f"field-class {parent_classes}" + + +class BoundFieldOverrideRenderer(DjangoTemplates): + bound_field_class = BoundFieldWithoutColon + + +@override_settings( + FORM_RENDERER="forms_tests.tests.test_forms.BoundFieldOverrideRenderer" +) +class CustomBoundFieldTest(SimpleTestCase): + def test_renderer_custom_bound_field(self): + t = Template("{{ form }}") + html = t.render(Context({"form": Person()})) + expected = """ + <div><label for="id_first_name">First name</label> + <input type="text" name="first_name" required + id="id_first_name"></div> + <div><label for="id_last_name">Last name</label> + <input type="text" name="last_name" required + id="id_last_name"></div><div> + <label for="id_birthday">Birthday</label> + <input type="text" name="birthday" required + id="id_birthday"></div>""" + self.assertHTMLEqual(html, expected) + + def test_form_custom_boundfield(self): + class CustomBoundFieldPerson(Person): + bound_field_class = BoundFieldWithTwoColons + + with self.subTest("form's BoundField takes over renderer's BoundField"): + t = Template("{{ form }}") + html = t.render(Context({"form": CustomBoundFieldPerson()})) + expected = """ + <div><label for="id_first_name">First name::</label> + <input type="text" name="first_name" required + id="id_first_name"></div> + <div><label for="id_last_name">Last name::</label> + <input type="text" name="last_name" required + id="id_last_name"></div><div> + <label for="id_birthday">Birthday::</label> + <input type="text" name="birthday" required + id="id_birthday"></div>""" + self.assertHTMLEqual(html, expected) + + with self.subTest("Constructor argument takes over class property"): + t = Template("{{ form }}") + html = t.render( + Context( + { + "form": CustomBoundFieldPerson( + bound_field_class=BoundFieldWithCustomClass + ) + } + ) + ) + expected = """ + <div><label class="custom-class" for="id_first_name">First name:</label> + <input type="text" name="first_name" required + id="id_first_name"></div> + <div><label class="custom-class" for="id_last_name">Last name:</label> + <input type="text" name="last_name" required + id="id_last_name"></div><div> + <label class="custom-class" for="id_birthday">Birthday:</label> + <input type="text" name="birthday" required + id="id_birthday"></div>""" + self.assertHTMLEqual(html, expected) + + with self.subTest("Overriding css_classes works as expected"): + t = Template("{{ form }}") + html = t.render( + Context( + { + "form": CustomBoundFieldPerson( + bound_field_class=BoundFieldWithWrappingClass + ) + } + ) + ) + expected = """ + <div class="field-class"><label for="id_first_name">First name:</label> + <input type="text" name="first_name" required + id="id_first_name"></div> + <div class="field-class"><label for="id_last_name">Last name:</label> + <input type="text" name="last_name" required + id="id_last_name"></div><div class="field-class"> + <label for="id_birthday">Birthday:</label> + <input type="text" name="birthday" required + id="id_birthday"></div>""" + self.assertHTMLEqual(html, expected) + + def test_field_custom_bound_field(self): + class BoundFieldWithTwoColonsCharField(CharField): + bound_field_class = BoundFieldWithTwoColons + + class CustomFieldBoundFieldPerson(Person): + bound_field_class = BoundField + + first_name = BoundFieldWithTwoColonsCharField() + last_name = BoundFieldWithTwoColonsCharField( + bound_field_class=BoundFieldWithCustomClass + ) + + html = Template("{{ form }}").render( + Context({"form": CustomFieldBoundFieldPerson()}) + ) + expected = """ + <div><label for="id_first_name">First name::</label> + <input type="text" name="first_name" required + id="id_first_name"></div> + <div><label class="custom-class" for="id_last_name">Last name:</label> + <input type="text" name="last_name" required + id="id_last_name"></div><div> + <label for="id_birthday">Birthday:</label> + <input type="text" name="birthday" required + id="id_birthday"></div>""" + self.assertHTMLEqual(html, expected) |
