From 587058e3c25aac4d871828a3ef19637eb9e8ddbd Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Tue, 8 Jan 2019 12:39:30 +0100 Subject: [PATCH] Allow run_validators() to handle non-dict types. (#6365) Fixes #6053. Original test case thanks to Vincent Delaitre in #6242. --- rest_framework/serializers.py | 7 +++++-- tests/test_serializer.py | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 110ffbfa9..eae08a34c 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -461,8 +461,11 @@ class Serializer(BaseSerializer): """ Add read_only fields with defaults to value before running validators. """ - to_validate = self._read_only_defaults() - to_validate.update(value) + if isinstance(value, dict): + to_validate = self._read_only_defaults() + to_validate.update(value) + else: + to_validate = value super(Serializer, self).run_validators(to_validate) def to_internal_value(self, data): diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 0650b7c57..efa1adf0e 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -156,6 +156,33 @@ class TestSerializer: assert serializer.validated_data == {'char': 'abc', 'integer': 123} assert serializer.errors == {} + def test_custom_to_internal_value(self): + """ + to_internal_value() is expected to return a dict, but subclasses may + return application specific type. + """ + class Point(object): + def __init__(self, srid, x, y): + self.srid = srid + self.coords = (x, y) + + # Declares a serializer that converts data into an object + class NestedPointSerializer(serializers.Serializer): + longitude = serializers.FloatField(source='x') + latitude = serializers.FloatField(source='y') + + def to_internal_value(self, data): + kwargs = super(NestedPointSerializer, self).to_internal_value(data) + return Point(srid=4326, **kwargs) + + serializer = NestedPointSerializer(data={'longitude': 6.958307, 'latitude': 50.941357}) + assert serializer.is_valid() + assert isinstance(serializer.validated_data, Point) + assert serializer.validated_data.srid == 4326 + assert serializer.validated_data.coords[0] == 6.958307 + assert serializer.validated_data.coords[1] == 50.941357 + assert serializer.errors == {} + class TestValidateMethod: def test_non_field_error_validate_method(self):