Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion django/forms/boundfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None):
if id_:
id_for_label = widget.id_for_label(id_)
if id_for_label:
attrs = {**(attrs or {}), "for": id_for_label}
attrs = attrs or {}
if tag != "legend":
attrs = {**attrs, "for": id_for_label}
if self.field.required and hasattr(self.form, "required_css_class"):
attrs = attrs or {}
if "class" in attrs:
Expand Down
6 changes: 6 additions & 0 deletions docs/ref/models/options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,12 @@ not be looking at your Django code. For example::

ordering = [F("author").asc(nulls_last=True)]

.. admonition:: Default ordering and GROUP BY

In :ref:`GROUP BY queries <aggregation-ordering-interaction>` (for example,
those using :meth:`~.QuerySet.values` and :meth:`~.QuerySet.annotate`), the
default ordering is not applied.

.. warning::

Ordering is not a free operation. Each field you add to the ordering
Expand Down
11 changes: 9 additions & 2 deletions docs/topics/db/aggregation.txt
Original file line number Diff line number Diff line change
Expand Up @@ -627,8 +627,15 @@ fields you also select in a ``values()`` call.
You might reasonably ask why Django doesn't remove the extraneous columns
for you. The main reason is consistency with ``distinct()`` and other
places: Django **never** removes ordering constraints that you have
specified (and we can't change those other methods' behavior, as that
would violate our :doc:`/misc/api-stability` policy).
specified *explicitly with* ``order_by()`` (and we can't change those
other methods' behavior, as that would violate our
:doc:`/misc/api-stability` policy).

.. admonition:: Default ordering not applied to GROUP BY

``GROUP BY`` queries (for example, those using ``.values()`` and
``.annotate()``) don't use the model's default ordering.
Use ``order_by()`` explicitly when a given order is needed.

Aggregating annotations
-----------------------
Expand Down
60 changes: 38 additions & 22 deletions tests/forms_tests/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3913,22 +3913,22 @@ class SomeForm(Form):
)
self.assertHTMLEqual(
f["field"].legend_tag(),
'<legend for="id_field" class="required">Field:</legend>',
'<legend class="required">Field:</legend>',
)
self.assertHTMLEqual(
f["field"].label_tag(attrs={"class": "foo"}),
'<label for="id_field" class="foo required">Field:</label>',
)
self.assertHTMLEqual(
f["field"].legend_tag(attrs={"class": "foo"}),
'<legend for="id_field" class="foo required">Field:</legend>',
'<legend class="foo required">Field:</legend>',
)
self.assertHTMLEqual(
f["field2"].label_tag(), '<label for="id_field2">Field2:</label>'
)
self.assertHTMLEqual(
f["field2"].legend_tag(),
'<legend for="id_field2">Field2:</legend>',
"<legend>Field2:</legend>",
)

def test_label_split_datetime_not_displayed(self):
Expand Down Expand Up @@ -4190,31 +4190,47 @@ class SomeForm(Form):

boundfield = SomeForm()["field"]

testcases = [ # (args, kwargs, expected)
# without anything: just print the <label>
((), {}, '<%(tag)s for="id_field">Field:</%(tag)s>'),
testcases = [ # (args, kwargs, expected_label, expected_legend)
# without anything: just print the <label>/<legend>
((), {}, '<label for="id_field">Field:</label>', "<legend>Field:</legend>"),
# passing just one argument: overrides the field's label
(("custom",), {}, '<%(tag)s for="id_field">custom:</%(tag)s>'),
(
("custom",),
{},
'<label for="id_field">custom:</label>',
"<legend>custom:</legend>",
),
# the overridden label is escaped
(("custom&",), {}, '<%(tag)s for="id_field">custom&amp;:</%(tag)s>'),
((mark_safe("custom&"),), {}, '<%(tag)s for="id_field">custom&:</%(tag)s>'),
# Passing attrs to add extra attributes on the <label>
(
("custom&",),
{},
'<label for="id_field">custom&amp;:</label>',
"<legend>custom&amp;:</legend>",
),
(
(mark_safe("custom&"),),
{},
'<label for="id_field">custom&:</label>',
"<legend>custom&:</legend>",
),
# Passing attrs to add extra attributes on the <label>/<legend>
(
(),
{"attrs": {"class": "pretty"}},
'<%(tag)s for="id_field" class="pretty">Field:</%(tag)s>',
'<label for="id_field" class="pretty">Field:</label>',
'<legend class="pretty">Field:</legend>',
),
]

for args, kwargs, expected in testcases:
for args, kwargs, expected_label, expected_legend in testcases:
with self.subTest(args=args, kwargs=kwargs):
self.assertHTMLEqual(
boundfield.label_tag(*args, **kwargs),
expected % {"tag": "label"},
expected_label,
)
self.assertHTMLEqual(
boundfield.legend_tag(*args, **kwargs),
expected % {"tag": "legend"},
expected_legend,
)

def test_boundfield_label_tag_no_id(self):
Expand Down Expand Up @@ -4252,7 +4268,7 @@ class SomeForm(Form):
)
self.assertHTMLEqual(
form["custom"].legend_tag(),
'<legend for="custom_id_custom">Custom:</legend>',
"<legend>Custom:</legend>",
)
self.assertHTMLEqual(form["empty"].label_tag(), "<label>Empty:</label>")
self.assertHTMLEqual(form["empty"].legend_tag(), "<legend>Empty:</legend>")
Expand All @@ -4266,7 +4282,7 @@ class SomeForm(Form):
self.assertHTMLEqual(boundfield.label_tag(), '<label for="id_field"></label>')
self.assertHTMLEqual(
boundfield.legend_tag(),
'<legend for="id_field"></legend>',
"<legend></legend>",
)

def test_boundfield_id_for_label(self):
Expand Down Expand Up @@ -4339,7 +4355,7 @@ class SomeForm(Form):
)
self.assertHTMLEqual(
boundfield.legend_tag(label_suffix="$"),
'<legend for="id_field">Field$</legend>',
"<legend>Field$</legend>",
)

def test_error_dict(self):
Expand Down Expand Up @@ -4879,7 +4895,7 @@ def test_label_does_not_include_new_line(self):
)
self.assertEqual(
field.legend_tag(),
'<legend for="id_first_name">First name:</legend>',
"<legend>First name:</legend>",
)

@override_settings(USE_THOUSAND_SEPARATOR=True)
Expand All @@ -4892,7 +4908,7 @@ def test_label_attrs_not_localized(self):
)
self.assertHTMLEqual(
field.legend_tag(attrs={"number": 9999}),
'<legend number="9999" for="id_first_name">First name:</legend>',
'<legend number="9999">First name:</legend>',
)

def test_remove_cached_field(self):
Expand Down Expand Up @@ -5204,12 +5220,12 @@ def clean(self):
self.assertHTMLEqual(
t.render(Context({"form": f})),
"<form>"
'<p><legend for="id_username">Username:</legend>'
"<p><legend>Username:</legend>"
'<input id="id_username" type="text" name="username" maxlength="10" '
'aria-describedby="id_username_helptext" required></p>'
'<p><legend for="id_password1">Password1:</legend>'
"<p><legend>Password1:</legend>"
'<input type="password" name="password1" id="id_password1" required></p>'
'<p><legend for="id_password2">Password2:</legend>'
"<p><legend>Password2:</legend>"
'<input type="password" name="password2" id="id_password2" required></p>'
'<input type="submit" required>'
"</form>",
Expand Down
4 changes: 2 additions & 2 deletions tests/forms_tests/tests/test_i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ class SomeForm(Form):
)
self.assertHTMLEqual(
f["field_1"].legend_tag(),
'<legend for="id_field_1">field_1:</legend>',
"<legend>field_1:</legend>",
)
self.assertHTMLEqual(
f["field_2"].label_tag(), '<label for="field_2_id">field_2:</label>'
)
self.assertHTMLEqual(
f["field_2"].legend_tag(),
'<legend for="field_2_id">field_2:</legend>',
"<legend>field_2:</legend>",
)

def test_non_ascii_choices(self):
Expand Down
6 changes: 3 additions & 3 deletions tests/forms_tests/widget_tests/test_clearablefileinput.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,12 +248,12 @@ class TestForm(Form):
form = TestForm()
self.assertIs(self.widget.use_fieldset, True)
self.assertHTMLEqual(
'<div><fieldset><legend for="id_field">Field:</legend>'
"<div><fieldset><legend>Field:</legend>"
'<input id="id_field" name="field" type="file" required></fieldset></div>'
'<div><fieldset><legend for="id_with_file">With file:</legend>Currently: '
"<div><fieldset><legend>With file:</legend>Currently: "
'<a href="something">something</a><br>Change:<input type="file" '
'name="with_file" id="id_with_file"></fieldset></div>'
'<div><fieldset><legend for="id_clearable_file">Clearable file:</legend>'
"<div><fieldset><legend>Clearable file:</legend>"
'Currently: <a href="something">something</a><input '
'type="checkbox" name="clearable_file-clear" id="clearable_file-clear_id">'
'<label for="clearable_file-clear_id">Clear</label><br>Change:'
Expand Down
2 changes: 1 addition & 1 deletion tests/forms_tests/widget_tests/test_selectdatewidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ class TestForm(Form):
form = TestForm()
self.assertIs(self.widget.use_fieldset, True)
self.assertHTMLEqual(
'<div><fieldset><legend for="id_field_month">Field:</legend>'
"<div><fieldset><legend>Field:</legend>"
'<select name="field_month" required id="id_field_month">'
'<option value="1">January</option><option value="2">February</option>'
'<option value="3">March</option><option value="4">April</option>'
Expand Down
6 changes: 3 additions & 3 deletions tests/model_forms/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,15 +977,15 @@ def test_label_overrides(self):
)
self.assertHTMLEqual(
form["name"].legend_tag(),
'<legend for="id_name">Title:</legend>',
"<legend>Title:</legend>",
)
self.assertHTMLEqual(
form["url"].legend_tag(),
'<legend for="id_url">The URL:</legend>',
"<legend>The URL:</legend>",
)
self.assertHTMLEqual(
form["slug"].legend_tag(),
'<legend for="id_slug">Slug:</legend>',
"<legend>Slug:</legend>",
)

def test_help_text_overrides(self):
Expand Down
4 changes: 2 additions & 2 deletions tests/model_formsets/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2161,7 +2161,7 @@ def test_modelformset_factory_labels_overrides(self):
)
self.assertHTMLEqual(
form["title"].legend_tag(),
'<legend for="id_title">Name:</legend>',
"<legend>Name:</legend>",
)

def test_inlineformset_factory_labels_overrides(self):
Expand All @@ -2174,7 +2174,7 @@ def test_inlineformset_factory_labels_overrides(self):
)
self.assertHTMLEqual(
form["title"].legend_tag(),
'<legend for="id_title">Name:</legend>',
"<legend>Name:</legend>",
)

def test_modelformset_factory_help_text_overrides(self):
Expand Down