1
0
mirror of https://github.com/django/django.git synced 2025-03-12 02:12:38 +00:00

Refs #31026 -- Removed BaseForm._html_output() per deprecation timeline.

This commit is contained in:
Mariusz Felisiak 2023-01-10 13:43:21 +01:00
parent 4982958ec0
commit 182d25eb7a
3 changed files with 3 additions and 228 deletions

View File

@ -13,7 +13,6 @@ from django.forms.widgets import Media, MediaDefiningClass
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from django.utils.deprecation import RemovedInDjango50Warning from django.utils.deprecation import RemovedInDjango50Warning
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.html import conditional_escape
from django.utils.safestring import SafeString, mark_safe from django.utils.safestring import SafeString, mark_safe
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
@ -219,99 +218,6 @@ class BaseForm(RenderableFormMixin):
# widgets split data over several HTML fields. # widgets split data over several HTML fields.
return widget.value_from_datadict(self.data, self.files, html_name) return widget.value_from_datadict(self.data, self.files, html_name)
def _html_output(
self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row
):
"Output HTML. Used by as_table(), as_ul(), as_p()."
warnings.warn(
"django.forms.BaseForm._html_output() is deprecated. "
"Please use .render() and .get_context() instead.",
RemovedInDjango50Warning,
stacklevel=2,
)
# Errors that should be displayed above all fields.
top_errors = self.non_field_errors().copy()
output, hidden_fields = [], []
for name, bf in self._bound_items():
field = bf.field
html_class_attr = ""
bf_errors = self.error_class(bf.errors)
if bf.is_hidden:
if bf_errors:
top_errors.extend(
[
_("(Hidden field %(name)s) %(error)s")
% {"name": name, "error": str(e)}
for e in bf_errors
]
)
hidden_fields.append(str(bf))
else:
# Create a 'class="..."' attribute if the row should have any
# CSS classes applied.
css_classes = bf.css_classes()
if css_classes:
html_class_attr = ' class="%s"' % css_classes
if errors_on_separate_row and bf_errors:
output.append(error_row % str(bf_errors))
if bf.label:
label = conditional_escape(bf.label)
label = bf.label_tag(label) or ""
else:
label = ""
if field.help_text:
help_text = help_text_html % field.help_text
else:
help_text = ""
output.append(
normal_row
% {
"errors": bf_errors,
"label": label,
"field": bf,
"help_text": help_text,
"html_class_attr": html_class_attr,
"css_classes": css_classes,
"field_name": bf.html_name,
}
)
if top_errors:
output.insert(0, error_row % top_errors)
if hidden_fields: # Insert any hidden fields in the last row.
str_hidden = "".join(hidden_fields)
if output:
last_row = output[-1]
# Chop off the trailing row_ender (e.g. '</td></tr>') and
# insert the hidden fields.
if not last_row.endswith(row_ender):
# This can happen in the as_p() case (and possibly others
# that users write): if there are only top errors, we may
# not be able to conscript the last row for our purposes,
# so insert a new, empty row.
last_row = normal_row % {
"errors": "",
"label": "",
"field": "",
"help_text": "",
"html_class_attr": html_class_attr,
"css_classes": "",
"field_name": "",
}
output.append(last_row)
output[-1] = last_row[: -len(row_ender)] + str_hidden + row_ender
else:
# If there aren't any rows in the output, just append the
# hidden fields.
output.append(str_hidden)
return mark_safe("\n".join(output))
@property @property
def template_name(self): def template_name(self):
return self.renderer.form_template_name return self.renderer.form_template_name

View File

@ -297,6 +297,8 @@ to remove usage of these features.
* The ``django.contrib.gis.admin.GeoModelAdmin`` and ``OSMGeoAdmin`` classes * The ``django.contrib.gis.admin.GeoModelAdmin`` and ``OSMGeoAdmin`` classes
are removed. are removed.
* The undocumented ``BaseForm._html_output()`` method is removed.
See :ref:`deprecated-features-4.1` for details on these changes, including how See :ref:`deprecated-features-4.1` for details on these changes, including how
to remove usage of these features. to remove usage of these features.

View File

@ -1,11 +1,9 @@
# RemovedInDjango50 # RemovedInDjango50
from django.forms import CharField, EmailField, Form, HiddenInput from django.forms import CharField, EmailField, Form
from django.forms.utils import ErrorList from django.forms.utils import ErrorList
from django.test import SimpleTestCase, ignore_warnings from django.test import SimpleTestCase, ignore_warnings
from django.utils.deprecation import RemovedInDjango50Warning from django.utils.deprecation import RemovedInDjango50Warning
from .test_forms import Person
class DivErrorList(ErrorList): class DivErrorList(ErrorList):
def __str__(self): def __str__(self):
@ -20,21 +18,6 @@ class DivErrorList(ErrorList):
class DeprecationTests(SimpleTestCase): class DeprecationTests(SimpleTestCase):
def test_deprecation_warning_html_output(self):
msg = (
"django.forms.BaseForm._html_output() is deprecated. Please use "
".render() and .get_context() instead."
)
with self.assertRaisesMessage(RemovedInDjango50Warning, msg):
form = Person()
form._html_output(
normal_row='<p id="p_%(field_name)s"></p>',
error_row="%s",
row_ender="</p>",
help_text_html=" %s",
errors_on_separate_row=True,
)
def test_deprecation_warning_error_list(self): def test_deprecation_warning_error_list(self):
class EmailForm(Form): class EmailForm(Form):
email = EmailField() email = EmailField()
@ -70,119 +53,3 @@ class DeprecatedTests(SimpleTestCase):
'<div class="error">This field is required.</div></div>' '<div class="error">This field is required.</div></div>'
'<p>Comment: <input type="text" name="comment" required></p>', '<p>Comment: <input type="text" name="comment" required></p>',
) )
def test_field_name(self):
"""#5749 - `field_name` may be used as a key in _html_output()."""
class SomeForm(Form):
some_field = CharField()
def as_p(self):
return self._html_output(
normal_row='<p id="p_%(field_name)s"></p>',
error_row="%s",
row_ender="</p>",
help_text_html=" %s",
errors_on_separate_row=True,
)
form = SomeForm()
self.assertHTMLEqual(form.as_p(), '<p id="p_some_field"></p>')
def test_field_without_css_classes(self):
"""
`css_classes` may be used as a key in _html_output() (empty classes).
"""
class SomeForm(Form):
some_field = CharField()
def as_p(self):
return self._html_output(
normal_row='<p class="%(css_classes)s"></p>',
error_row="%s",
row_ender="</p>",
help_text_html=" %s",
errors_on_separate_row=True,
)
form = SomeForm()
self.assertHTMLEqual(form.as_p(), '<p class=""></p>')
def test_field_with_css_class(self):
"""
`css_classes` may be used as a key in _html_output() (class comes
from required_css_class in this case).
"""
class SomeForm(Form):
some_field = CharField()
required_css_class = "foo"
def as_p(self):
return self._html_output(
normal_row='<p class="%(css_classes)s"></p>',
error_row="%s",
row_ender="</p>",
help_text_html=" %s",
errors_on_separate_row=True,
)
form = SomeForm()
self.assertHTMLEqual(form.as_p(), '<p class="foo"></p>')
def test_field_name_with_hidden_input(self):
"""
BaseForm._html_output() should merge all the hidden input fields and
put them in the last row.
"""
class SomeForm(Form):
hidden1 = CharField(widget=HiddenInput)
custom = CharField()
hidden2 = CharField(widget=HiddenInput)
def as_p(self):
return self._html_output(
normal_row="<p%(html_class_attr)s>%(field)s %(field_name)s</p>",
error_row="%s",
row_ender="</p>",
help_text_html=" %s",
errors_on_separate_row=True,
)
form = SomeForm()
self.assertHTMLEqual(
form.as_p(),
'<p><input id="id_custom" name="custom" type="text" required> custom'
'<input id="id_hidden1" name="hidden1" type="hidden">'
'<input id="id_hidden2" name="hidden2" type="hidden"></p>',
)
def test_field_name_with_hidden_input_and_non_matching_row_ender(self):
"""
BaseForm._html_output() should merge all the hidden input fields and
put them in the last row ended with the specific row ender.
"""
class SomeForm(Form):
hidden1 = CharField(widget=HiddenInput)
custom = CharField()
hidden2 = CharField(widget=HiddenInput)
def as_p(self):
return self._html_output(
normal_row="<p%(html_class_attr)s>%(field)s %(field_name)s</p>",
error_row="%s",
row_ender="<hr><hr>",
help_text_html=" %s",
errors_on_separate_row=True,
)
form = SomeForm()
self.assertHTMLEqual(
form.as_p(),
'<p><input id="id_custom" name="custom" type="text" required> custom</p>\n'
'<input id="id_hidden1" name="hidden1" type="hidden">'
'<input id="id_hidden2" name="hidden2" type="hidden"><hr><hr>',
)