I have a question regarding validation logic of serializers.ChoiceField
. As I've seen in the code, here is to_internal_value()
of ChoiceField
that is used to validate client inputs:
def to_internal_value(self, data):
if data == '' and self.allow_blank:
return ''
try:
return self.choice_strings_to_values[six.text_type(data)]
except KeyError:
self.fail('invalid_choice', input=data)
Here is my declaration of Django model:
class MyModel(BaseModel, ScopedModelMixin):
my_field = models.FloatField(choices=MY_FLOAT_CHOICES, default=MY_FLOAT_CHOICES.default_value)
And here is my declaration of choices object from django-model-utils==2.6.1
:
from model_utils import Choices
MY_FLOAT_CHOICES = Choices(
(1.0, 'choice1', 'Choice1'),
(1.5, 'default_value', 'Choice2'),
(2.0, 'choice3', 'Choice3')
)
So, the generated field in a model serializer is a serializers.ChoiceField
with choices provided at the previously declared model level.
When it comes to validation user input from the client, DRF fails to validate float values correctly. For example, when I send:
{
"myField": 1
}
it throws "\"1\" is not a valid choice."
. So when I come with debugger to the line
return self.choice_strings_to_values[six.text_type(data)]
from previously shown to_internal()
of ChoiceField
, I see that it literally tries to find '1'
in choices list. When I update my choices with:
MY_FLOAT_CHOICES = Choices(
(1, 'choice1', 'Choice1'),
(1.5, 'default_value', 'Choice2'),
(2, 'choice3', 'Choice3')
)
it doesn't fail, but then I have the same problem with sending 1.0
instead from 1
and it goes round and round. Should I raise an issue on the DRF repository, or there is some better option?
I guess you have to convert the int key to float so it will be able to find it in the choices tuple.