https://github.com/validator/validator/issues/47
This is how I could explain it:
If a form field is required and has the `empty_label=True` argument, the
generated `<select>` will have a `required="required"` attribute. This
doesn't make sense since the first item will be selected anyways, and
there is no way for the user to ''unselect'' a value.
So, the `required="required"` attribute is useless.
Example:
{{{#!python
class TestForm(forms.Form):
some_field = forms.ModelChoiceField(queryset=SomeModel.objects.all(),
empty_label=None)
}}}
results in:
{{{#!text/html
<select id="id_some_field" name="some_field" required>
<option value="1">Value 1</option>
<option value="2">Value 2</option>
<option value="3">Value 3</option>
<!-- ... -->
</select>
}}}
You can check the following code using the
[https://validator.w3.org/#validate_by_input W3C validation service]:
{{{#!text/html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Validation test</title>
</head>
<body>
<select id="id_some_field" name="some_field" required>
<option value="1">Value 1</option>
<option value="2">Value 2</option>
<option value="3">Value 3</option>
<!-- ... -->
</select>
</body>
</html>
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27370>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* needs_better_patch: => 0
* needs_tests: => 0
* needs_docs: => 0
Old description:
New description:
I didn't think it was wrong in HTML, but the W3C validator says so, and
after reading this discussion, it seems to be right:
https://github.com/validator/validator/issues/47
Example:
results in:
--
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:1>
Old description:
> I didn't think it was wrong in HTML, but the W3C validator says so, and
> after reading this discussion, it seems to be right:
New description:
I didn't think it was wrong in HTML, but the W3C validator says so, and
after reading this discussion, it seems to be right:
https://github.com/validator/validator/issues/47
Example:
results in:
In order to fix this, the generated `<select>` widget should not have a
`required` attribute.
--
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:2>
* version: 1.10 => master
* type: Bug => Cleanup/optimization
* stage: Unreviewed => Accepted
Comment:
Here's the validator error message:
`The first child option element of a select element with a required
attribute, and without a multiple attribute, and without a size attribute
whose value is greater than 1, must have either an empty value attribute,
or must have no text content. Consider either adding a placeholder option
label, or adding a size attribute with a value equal to the number of
option elements.`
At first sight, this should be doable without difficulty in the widget's
`use_required_attribute` method.
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:3>
Comment (by Andrew Nester):
Agree with Claude Paroz - all we need to do is to set
{{{use_required_attribute = False}}} in form where such field used.
Something like this:
{{{
class TestForm(forms.Form):
use_required_attribute = False
some_field = forms.ModelChoiceField(queryset=SomeModel.objects.all(),
empty_label=None)
}}}
I guess we don't need some additional changes for this, what do you think
@alexpirine?
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:4>
Comment (by Claude Paroz):
If Django has all needed elements to determine the value of
`use_required_attribute` in such a situation, it should do it
automatically and not require the user to add it explicitly.
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:5>
Comment (by alexpirine):
I agree with Claude.
Also, `use_required_attribute` applies to all fields, which is not desired
here. We only want to remove the required attribute from the Select
widget.
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:6>
Comment (by Jon Dufresne):
alexpirine, I believe Claude is referring to
[https://github.com/django/django/blob/adc93e85990b644194c679f528225deed9fdaa85/django/forms/widgets.py#L254-L255
Widget.use_required_attribute], not `Form.use_required_attribute`. For
reference, this method will be documented
[https://github.com/django/django/pull/7419 soon].
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:7>
* owner: nobody => Josef Rousek
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:8>
* has_patch: 0 => 1
Comment:
[https://github.com/django/django/pull/7497 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:9>
Comment (by alexpirine):
I reviewed the code:
The overall logic and tests seem to be correct, except in case of an empty
<select>.
But I can not make a full judgment about the code, since I lack the
understanding of some parts of `widgets.py`. For instance I didn't know
anything about the `renderer` attribute (I still can not find it in
documentation).
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:10>
Comment (by Josef Rousek):
Replying to [comment:10 alexpirine]:
> I reviewed the code:
>
> The overall logic and tests seem to be correct, except in case of an
empty <select>.
>
> But I can not make a full judgment about the code, since I lack the
understanding of some parts of `widgets.py`. For instance I didn't know
anything about the `renderer` attribute (I still can not find it in
documentation).
Thanks for review! I'll fix those issues.
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:11>
* stage: Accepted => Ready for checkin
Comment:
Patch LGTM pending some cosmetic comments.
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:12>
Comment (by Josef Rousek):
I applied those cosmetic changes.
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:13>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"aaecf038cae61f114db396f74e06759c95f21e93" aaecf038]:
{{{
#!CommitTicketReference repository=""
revision="aaecf038cae61f114db396f74e06759c95f21e93"
Fixed #27370 -- Prevented Select widget from using 'required' with a non-
empty first value.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:14>
Comment (by Aurélien Pardon):
There is a huge performance regression as a side-effect of
[changeset:"aaecf038cae61f114db396f74e06759c95f21e93" aaecf038]. For
{{{ModelChoiceField}}} with {{{empty_label=None}}}, it doubles the queries
to the database.
With this {{{simple_app/models.py}}}:
{{{#!python
from django.db import models
class MyModel(models.Model):
my_field = models.CharField(max_length=1)
}}}
the following code:
{{{#!python
from django import forms
from simple_app.models import MyModel
class MyForm(forms.Form):
my_form_field = forms.ModelChoiceField(MyModel.objects.all(),
empty_label=None)
MyForm().as_ul()
}}}
makes two times the same request to the database:
{{{#!python
>>> from django.db import connection
>>> from django.db import reset_queries
>>> reset_queries()
>>> _ = MyForm().as_ul()
>>> connection.queries
[{'sql': 'SELECT "simple_app_mymodel"."id",
"simple_app_mymodel"."my_field" FROM "simple_app_mymodel"',
'time': '0.000'},
{'sql': 'SELECT "simple_app_mymodel"."id",
"simple_app_mymodel"."my_field" FROM "simple_app_mymodel"',
'time': '0.000'}]
}}}
Before this commit, it only makes one request (as intended IMO):
{{{#!python
>>> from django.db import connection
>>> from django.db import reset_queries
>>> reset_queries()
>>> _ = MyForm().as_ul()
>>> connection.queries
[{'sql': 'SELECT "simple_app_mymodel"."id",
"simple_app_mymodel"."my_field" FROM "simple_app_mymodel"',
'time': '0.000'}]
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:15>
* cc: Aurélien Pardon (added)
* needs_better_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:16>
* needs_better_patch: 1 => 0
Comment:
Follow-up in #31295.
--
Ticket URL: <https://code.djangoproject.com/ticket/27370#comment:17>