Skip to content

Commit e37619f

Browse files
authored
Serializer defaults should not be included in partial updates. (#4346)
Serializer default values should not be included in partial updates
1 parent 296e47a commit e37619f

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

docs/api-guide/fields.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ Defaults to `False`
4949

5050
### `default`
5151

52-
If set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behavior is to not populate the attribute at all.
52+
If set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behaviour is to not populate the attribute at all.
53+
54+
The `default` is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.
5355

5456
May be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a `set_context` method, that will be called each time before getting the value with the field instance as only argument. This works the same way as for [validators](validators.md#using-set_context).
5557

rest_framework/fields.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,8 @@ def get_default(self):
435435
return `empty`, indicating that no value should be set in the
436436
validated data for this field.
437437
"""
438-
if self.default is empty:
438+
if self.default is empty or getattr(self.root, 'partial', False):
439+
# No default, or this is a partial update.
439440
raise SkipField()
440441
if callable(self.default):
441442
if hasattr(self.default, 'set_context'):

tests/test_serializer.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,31 @@ class ExampleSerializer(serializers.Serializer):
309309
pickled = pickle.dumps(serializer.data)
310310
data = pickle.loads(pickled)
311311
assert data == {'field1': 'a', 'field2': 'b'}
312+
313+
314+
class TestDefaultInclusions:
315+
def setup(self):
316+
class ExampleSerializer(serializers.Serializer):
317+
char = serializers.CharField(read_only=True, default='abc')
318+
integer = serializers.IntegerField()
319+
self.Serializer = ExampleSerializer
320+
321+
def test_default_should_included_on_create(self):
322+
serializer = self.Serializer(data={'integer': 456})
323+
assert serializer.is_valid()
324+
assert serializer.validated_data == {'char': 'abc', 'integer': 456}
325+
assert serializer.errors == {}
326+
327+
def test_default_should_be_included_on_update(self):
328+
instance = MockObject(char='def', integer=123)
329+
serializer = self.Serializer(instance, data={'integer': 456})
330+
assert serializer.is_valid()
331+
assert serializer.validated_data == {'char': 'abc', 'integer': 456}
332+
assert serializer.errors == {}
333+
334+
def test_default_should_not_be_included_on_partial_update(self):
335+
instance = MockObject(char='def', integer=123)
336+
serializer = self.Serializer(instance, data={'integer': 456}, partial=True)
337+
assert serializer.is_valid()
338+
assert serializer.validated_data == {'integer': 456}
339+
assert serializer.errors == {}

0 commit comments

Comments
 (0)