#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.

Reply via email to