Skip to content

Commit 24c9c45

Browse files
committed
Allow for missing non-required nested objects.
Serializer fields which are themselves serializers should not be required. Specifically, if a nested object is set to "required=False", it should be possible to serialize the main object and have the sub-object set to None/null.
1 parent 1154d87 commit 24c9c45

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

rest_framework/fields.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def get_component(obj, attr_name):
5050
return that attribute on the object.
5151
"""
5252
if isinstance(obj, dict):
53-
val = obj[attr_name]
53+
val = obj.get(attr_name)
5454
else:
5555
val = getattr(obj, attr_name)
5656

rest_framework/tests/serializer.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ def restore_object(self, data, instance=None):
4343
return instance
4444

4545

46+
class NamesSerializer(serializers.Serializer):
47+
first = serializers.CharField()
48+
last = serializers.CharField(required=False, default='')
49+
initials = serializers.CharField(required=False, default='')
50+
51+
52+
class PersonIdentifierSerializer(serializers.Serializer):
53+
ssn = serializers.CharField()
54+
names = NamesSerializer(source='names', required=False)
55+
56+
4657
class BookSerializer(serializers.ModelSerializer):
4758
isbn = serializers.RegexField(regex=r'^[0-9]{13}$', error_messages={'invalid': 'isbn has to be exact 13 numbers'})
4859

@@ -141,6 +152,42 @@ def test_create(self):
141152
self.assertFalse(serializer.object is expected)
142153
self.assertEqual(serializer.data['sub_comment'], 'And Merry Christmas!')
143154

155+
def test_create_nested(self):
156+
"""Test a serializer with nested data."""
157+
names = {'first': 'John', 'last': 'Doe', 'initials': 'jd'}
158+
data = {'ssn': '1234567890', 'names': names}
159+
serializer = PersonIdentifierSerializer(data=data)
160+
161+
self.assertEqual(serializer.is_valid(), True)
162+
self.assertEqual(serializer.object, data)
163+
self.assertFalse(serializer.object is data)
164+
self.assertEqual(serializer.data['names'], names)
165+
166+
def test_create_partial_nested(self):
167+
"""Test a serializer with nested data which has missing fields."""
168+
names = {'first': 'John'}
169+
data = {'ssn': '1234567890', 'names': names}
170+
serializer = PersonIdentifierSerializer(data=data)
171+
172+
expected_names = {'first': 'John', 'last': '', 'initials': ''}
173+
data['names'] = expected_names
174+
175+
self.assertEqual(serializer.is_valid(), True)
176+
self.assertEqual(serializer.object, data)
177+
self.assertFalse(serializer.object is expected_names)
178+
self.assertEqual(serializer.data['names'], expected_names)
179+
180+
def test_null_nested(self):
181+
"""Test a serializer with a nonexistent nested field"""
182+
data = {'ssn': '1234567890'}
183+
serializer = PersonIdentifierSerializer(data=data)
184+
185+
self.assertEqual(serializer.is_valid(), True)
186+
self.assertEqual(serializer.object, data)
187+
self.assertFalse(serializer.object is data)
188+
expected = {'ssn': '1234567890', 'names': None}
189+
self.assertEqual(serializer.data, expected)
190+
144191
def test_update(self):
145192
serializer = CommentSerializer(self.comment, data=self.data)
146193
expected = self.comment

0 commit comments

Comments
 (0)