From 9f21095a1116ff8eff656358fc66142614b88c9a Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Mon, 9 Oct 2017 10:22:34 -0400 Subject: [PATCH 1/2] Add docs note on dotted source + default value --- docs/api-guide/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index c9c2c83a53..3d2443c5c8 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -61,7 +61,7 @@ Note that setting a `default` value implies that the field is not required. Incl ### `source` -The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `URLField(source='get_absolute_url')`, or may use dotted notation to traverse attributes, such as `EmailField(source='user.email')`. +The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `URLField(source='get_absolute_url')`, or may use dotted notation to traverse attributes, such as `EmailField(source='user.email')`. When serializing fields with dotted notation, it may be necessary to provide a `default` value if any object is not present or is empty during attribute traversal. The value `source='*'` has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation. From 3e15e7879d526d3cee151202b87a98d1c9c505a7 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Mon, 9 Oct 2017 10:23:17 -0400 Subject: [PATCH 2/2] Add additional dotted source tests --- tests/test_serializer.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index af5206a9f9..bb78af63af 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -424,6 +424,31 @@ class Serializer(serializers.Serializer): assert Serializer({'traversed': {'attr': 'abc'}}).data == {'traversed': 'abc'} + def test_default_for_multiple_dotted_source(self): + class Serializer(serializers.Serializer): + c = serializers.CharField(default='x', source='a.b.c') + + assert Serializer({}).data == {'c': 'x'} + assert Serializer({'a': {}}).data == {'c': 'x'} + assert Serializer({'a': None}).data == {'c': 'x'} + assert Serializer({'a': {'b': {}}}).data == {'c': 'x'} + assert Serializer({'a': {'b': None}}).data == {'c': 'x'} + + assert Serializer({'a': {'b': {'c': 'abc'}}}).data == {'c': 'abc'} + + def test_default_for_nested_serializer(self): + class NestedSerializer(serializers.Serializer): + a = serializers.CharField(default='1') + c = serializers.CharField(default='2', source='b.c') + + class Serializer(serializers.Serializer): + nested = NestedSerializer() + + assert Serializer({'nested': None}).data == {'nested': None} + assert Serializer({'nested': {}}).data == {'nested': {'a': '1', 'c': '2'}} + assert Serializer({'nested': {'a': '3', 'b': {}}}).data == {'nested': {'a': '3', 'c': '2'}} + assert Serializer({'nested': {'a': '3', 'b': {'c': '4'}}}).data == {'nested': {'a': '3', 'c': '4'}} + class TestCacheSerializerData: def test_cache_serializer_data(self):