Opened 16 months ago
Closed 16 months ago
#34721 closed Bug (invalid)
ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion not applied.
Reported by: | Daniel | Owned by: | nobody |
---|---|---|---|
Component: | Forms | Version: | 4.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Given a form like
# forms.py class MyForm(Form): colour = ChoiceField( choices=[(0, "Red"), (1, "Green"), (2, "Blue"), (3, "Yellow")], initial=0, widget=HiddenInput(), required=True, ) # views.py def my_view(request): my_form = MyForm(request.POST or None) ... return render(request,"template.html", { "my_form": my_form })
and a template like
{% for colour_id, colour in my_form.fields.colour.choices %} {{ colour }}: {% if colour_id == my_form.colour.value %}selected{% else %}not selected{% endif %} {% endfor %}
I find inconsistent behaviour in the return type of my_form["colour"]
, or {{ my_form.colour.value }}
respectively.
my_form.fields["colour"].choices
, and {{ my_form.fields.colour.choices }}
correctly return the list of tuples assigned to the choices=
parameter of the ChoiceField
, retaining their types. Hence, colour_id
and colour
are of type int
and string
respectively.
If the form is unbound and the fields initial=
value is used, then my_form["colour"]
, and {{ my_form.colour.value }}
return the initial value of 0
as type int
.
If the form is bound, then my_form["colour"]
, and {{ my_form.colour.value }}
return the selected choice as type str
.
I would expect that all, my_form.fields["colour"].choices
and {{ my_form.fields.colour.choices }}
and my_form["colour"]
and {{ my_form.colour.value }}
would return the values as the same type.
Changing ChoiceField(...)
to TypedChoiceField(..., coerce=int)
does only affect my_form.cleaned_data["colour"]
, but neither of my_form.fields["colour"].choices
,{{ my_form.fields.colour.choices }}
, or my_form["colour"]
, or{{ my_form.colour.value }}
.
Ultimately leads to {% if colour_id == my_form.colour.value %}
never being true when the form is bound, even when it should.
Attachments (1)
Change History (6)
comment:1 by , 16 months ago
Description: | modified (diff) |
---|
follow-up: 3 comment:2 by , 16 months ago
Resolution: | → worksforme |
---|---|
Status: | new → closed |
comment:3 by , 16 months ago
Replying to Natalia Bidart:
Hello,
From my initial testing, and using as a base the code you shared, the template shows the expected behavior: when
request.POST
is empty, then data isNone
and I seeRed
as selected which is the default. If I hard codedata
to be, for example,{"colour": 3}
, I seeYellow
as selected.
Because of the above, the best place to get answers to your issue is using any of the user support channels from this link. Since the goal of this issue tracker is to track issues about Django itself, and your issue seems, at first, to be located in your custom code, I'll be closing this ticket as invalid.
If, after debugging, you find out that this is indeed a bug in Django, please re-open with the specific details.
Thank you!
Hi Natalia,
my description of the issue is accurate and you did not properly inspect the data. It is a bug.
A sample is attached.
comment:4 by , 16 months ago
Resolution: | worksforme |
---|---|
Status: | closed → new |
comment:5 by , 16 months ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
Changing
ChoiceField(...)
toTypedChoiceField(..., coerce=int)
does only affectmy_form.cleaned_data["colour"]
, but neither ofmy_form.fields["colour"].choices
,{{ my_form.fields.colour.choices }}
, ormy_form["colour"]
, or{{ my_form.colour.value }}
.
Yes, and that's exactly what you should use, TypedChoiceField
and cleaned_data
.
Ultimately leads to
{% if colour_id == my_form.colour.value %}
never being true when the form is bound, even when it should.
That's an incorrect expectation. BoundField.value()
is the raw value of the field. If you're having trouble understanding how Django works, see TicketClosingReasons/UseSupportChannels for ways to get help.
Hello,
From my initial testing, and using as a base the code you shared, the template shows the expected behavior: when
request.POST
is empty, then data isNone
and I seeRed
as selected which is the default. If I hard codedata
to be, for example,{"colour": 3}
, I seeYellow
as selected.Because of the above, the best place to get answers to your issue is using any of the user support channels from this link. Since the goal of this issue tracker is to track issues about Django itself, and your issue seems, at first, to be located in your custom code, I'll be closing this ticket as invalid.
If, after debugging, you find out that this is indeed a bug in Django, please re-open with the specific details.
Thank you!