[Django] #34721: ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion not applied.

15 views
Skip to first unread message

Django

unread,
Jul 18, 2023, 2:07:50 PM7/18/23
to django-...@googlegroups.com
#34721: ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion
not applied.
--------------------------------------+------------------------
Reporter: Daniel | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 4.2
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
--------------------------------------+------------------------
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 }}`.

--
Ticket URL: <https://code.djangoproject.com/ticket/34721>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jul 18, 2023, 2:10:36 PM7/18/23
to django-...@googlegroups.com
#34721: ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion
not applied.
------------------------+--------------------------------------

Reporter: Daniel | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 4.2
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------+--------------------------------------
Description changed by Daniel:

Old description:

New description:

Given a form like

and a template like

Ultimately leads to `{% if colour_id == my_form.colour.value %}` never
being true when the form is bound, even when it should.

--

--
Ticket URL: <https://code.djangoproject.com/ticket/34721#comment:1>

Django

unread,
Jul 18, 2023, 2:43:08 PM7/18/23
to django-...@googlegroups.com
#34721: ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion
not applied.
------------------------+--------------------------------------
Reporter: Daniel | Owner: nobody
Type: Bug | Status: closed
Component: Forms | Version: 4.2
Severity: Normal | Resolution: worksforme

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------+--------------------------------------
Changes (by Natalia Bidart):

* status: new => closed
* resolution: => worksforme


Comment:

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 is `None` and I see `Red` as selected which is the default. If I hard
code `data` to be, for example, `{"colour": 3}`, I see `Yellow` as
selected.

Because of the above, the best place to get answers to your issue is using
any of the user support channels from
[https://docs.djangoproject.com/en/dev/faq/help/#how-do-i-do-x-why-
doesn-t-y-work-where-can-i-go-to-get-help 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!

--
Ticket URL: <https://code.djangoproject.com/ticket/34721#comment:2>

Django

unread,
Jul 18, 2023, 3:26:04 PM7/18/23
to django-...@googlegroups.com
#34721: ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion
not applied.
------------------------+--------------------------------------
Reporter: Daniel | Owner: nobody
Type: Bug | Status: closed
Component: Forms | Version: 4.2
Severity: Normal | Resolution: worksforme
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------+--------------------------------------
Changes (by Daniel):

* Attachment "Sample.zip" added.

Sample Project

Django

unread,
Jul 18, 2023, 3:27:16 PM7/18/23
to django-...@googlegroups.com
#34721: ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion
not applied.
------------------------+--------------------------------------
Reporter: Daniel | Owner: nobody
Type: Bug | Status: closed
Component: Forms | Version: 4.2
Severity: Normal | Resolution: worksforme
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------+--------------------------------------

Comment (by Daniel):

Replying to [comment:2 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 is `None` and I see `Red` as selected which is the default. If I hard
code `data` to be, for example, `{"colour": 3}`, I see `Yellow` as
selected.
>
> Because of the above, the best place to get answers to your issue is
using any of the user support channels from
[https://docs.djangoproject.com/en/dev/faq/help/#how-do-i-do-x-why-
doesn-t-y-work-where-can-i-go-to-get-help 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.

--
Ticket URL: <https://code.djangoproject.com/ticket/34721#comment:3>

Django

unread,
Jul 18, 2023, 3:30:05 PM7/18/23
to django-...@googlegroups.com
#34721: ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion
not applied.
------------------------+--------------------------------------
Reporter: Daniel | Owner: nobody
Type: Bug | Status: new

Component: Forms | Version: 4.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------+--------------------------------------
Changes (by Daniel):

* status: closed => new
* resolution: worksforme =>


--
Ticket URL: <https://code.djangoproject.com/ticket/34721#comment:4>

Django

unread,
Jul 18, 2023, 11:42:48 PM7/18/23
to django-...@googlegroups.com
#34721: ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion
not applied.
------------------------+--------------------------------------
Reporter: Daniel | Owner: nobody
Type: Bug | Status: closed
Component: Forms | Version: 4.2
Severity: Normal | Resolution: invalid

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------+--------------------------------------
Changes (by Mariusz Felisiak):

* status: new => closed

* resolution: => invalid


Comment:

> 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 }}`.

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.

--
Ticket URL: <https://code.djangoproject.com/ticket/34721#comment:5>

Reply all
Reply to author
Forward
0 new messages