encode / django-rest-framework

Web APIs for Django. 🎸
https://www.django-rest-framework.org
Other
28.38k stars 6.84k forks source link

Choice Field validate the value before calling validate in serializer #5876

Closed peeomid closed 6 years ago

peeomid commented 6 years ago

Checklist

Steps to reproduce

I have a model with choice field (this is from fcm-django)

class FCMDevice(Device):
    DEVICE_TYPES = (
        (u'ios', u'ios'),
        (u'android', u'android'),
        (u'web', u'web')
    )

    type = models.CharField(choices=DEVICE_TYPES, max_length=10)

And in its serializer, I try to convert type to lower case

class FCMDeviceSerializer(ModelSerializer):
    class Meta(DeviceSerializerMixin.Meta):
        model = FCMDevice

    def validate_type(self, value):
        return value.lower()

Expected behavior

So when I pass value "IOS", it should convert to "ios" before validating with choices.

Actual behavior

It actually raises validation error before being validated

{'type': ['"IOS" is not a valid choice.']}
carltongibson commented 6 years ago

This is expected behaviour.

https://github.com/encode/django-rest-framework/blob/0da461710ad552c401a47b29b93e829ce879a696/rest_framework/serializers.py#L461-L468

Base field-level validation is applied before the additional serialiser-level methods are called.

Your best bet is to subclass the field and override to_internal_value to make the lower() call.

peeomid commented 6 years ago

Thanks a lot for such quick response @carltongibson, and thanks for pointing out the suggestion.

Just curious about this design though, as I thought serializer would be wrapper on top, before executing model level thing?