From 6221124e0d54816d885ae64b963c9b41bfbc74ff Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Mon, 16 Oct 2017 05:33:46 -0400 Subject: [PATCH] Docs about default value for dotted source, additional tests (#5489) * Add docs note on dotted source + default value * Add additional dotted source tests --- docs/api-guide/fields.md | 2 +- tests/test_serializer.py | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index c9c2c83a5..3d2443c5c 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. diff --git a/tests/test_serializer.py b/tests/test_serializer.py index af5206a9f..bb78af63a 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -424,6 +424,31 @@ class TestDefaultOutput: 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):