#34156: TypedChoiceField not compatible with IntegerChoices
-------------------------------------+-------------------------------------
Reporter: | Owner: nobody
yoshiohasegawa |
Type: Bug | Status: new
Component: Forms | Version: 4.1
Severity: Normal | Keywords: Form,
| TypedChoiceField, IntegerChoices,
Triage Stage: | Coercion
Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Coercion always fails when using IntegerChoices with a TypedChoiceField in
a Django form.
When a value is cleaned in a TypedChoiceField, the inherited ChoiceField's
`to_python()` method will return the value casted as a string. This means
that when coercion with an IntegerChoices object is attempted, it will
always fail as IntegerChoices will expect an int type when instantiated.
=== Example ===
{{{#!python
class SomeIntegerChoice(models.IntegerChoices):
VAL_2350 = (2350, "value 2350")
VAL_4100 = (4100, "value 4100")
VAL_8760 = (8760, "value 8760")
}}}
{{{#!python
form.fields["Integer_choice"] = forms.TypedChoiceField(
required=required,
choices=SomeIntegerChoice.choices,
coerce=SomeIntegerChoice,
)
}}}
This field will never pass validation since `ChoiceField` (inherited by
`TypedChoiceField`) has a `to_python()` method that casts the provided
value as a string:
{{{#!python
# class ChoiceField:
# ...
def to_python(self, value):
"""Return a string."""
if value in self.empty_values:
return ""
return str(value)
}}}
To explain further... `ChoiceField.to_python()` will be called when
`TypedChoiceField` attempts to `clean()` a value. After the value is
cleaned, it is coerced using the provided class definition via the
`coerce` property.
Here is example code from Django to show how this happens:
{{{#!python
# class TypedChoiceField:
# ...
def _coerce(self, value):
"""
Validate that the value can be coerced to the right type (if not
empty).
"""
if value == self.empty_value or value in self.empty_values:
return self.empty_value
try:
value = self.coerce(value)
except (ValueError, TypeError, ValidationError):
raise ValidationError(
self.error_messages["invalid_choice"],
code="invalid_choice",
params={"value": value},
)
return value
def clean(self, value):
value = super().clean(value)
return self._coerce(value)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34156>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/0107018476381e07-866fd597-0fed-45d6-acea-2043f8daa1ee-000000%40eu-central-1.amazonses.com.