Search code examples
django-rest-frameworkdjango-serializer

django serializer validate field method wrong interpretation


I should be wrong in my conclusion but I can't understand this in another way. with this model:

class ExampleSerializer(serializers.Serializer):
    field = serializers.CharField()

Normally django checks the field by it's own before working with the model, so you can't use c_field as interger because it's a char field.

Now, I want to add custom validation:

class ExampleSerializer(serializers.Serializer): field = serializers.CharField()

def validate_field(self, data):
    if data == 'correct':
          return 'good'
    else:
          raise serializers.ValidationError('wrong data')

for me, it should be the correct way to use it, it add another 'validation' to that field, but I see it's been using in this way:

class ExampleSerializer(serializers.Serializer): field = serializers.CharField()

def validate_field(self, data):
    if data == 'correct':
          return {'data': data}

and I don't understand it, because, it's returns something different, if you check it with:

res = serializer.ExampleSerializer(data={'field': 'field_char'})
res.is_valid()
res.data

and now data is a dict... And here is what I don't understand, you can change it, so anyone that see the serializer get confused (and if you have a lot of validators you need to look for the correct one to understand what's happening), and the name it's confused to, because it's 'validate', not 'read_modify' or whatever.

So, I think it's another explanation that I can't find and understand. Any idea?


Solution

  • Explanation

    Your use case of the first should be the preferred way. Using custom field-level validation by implementing a method in serializer with validate_<field_name> name, should return the same data type as the actual field. More details can be found here.

    The reason why this code

    res = serializer.ExampleSerializer(data={'field': 'field_char'})
    res.is_valid()
    res.data
    

    returns something different from what you expect it to be is because you access a wrong attribute.

    • .data is the value of what will be serialized into JSON.
    • .validated_data is the value of what will be deserialized into python object. Meaning that value that is returned from field-level validation via validate_<field_name> method in serializer will be the value of a field in .validated_data.

    Notes

    If you want to perform multiple validations on a single field without mutating the value, you should use validators