Opened 16 months ago

Last modified 16 months ago

#34721 closed Bug

ChoiceField/TypedChoiceField: .value() has inconsistent behaviour, coercion not applied. — at Version 1

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 Daniel)

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.

Change History (1)

comment:1 by Daniel, 16 months ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top