Commit cf5d401a by Tibo Beijen Committed by Tom Christie

Allow required false and default (#4692)

* Default value will now be used when serializing if key or attribute is missing.
parent 8a14b39e
...@@ -55,6 +55,8 @@ The `default` is not applied during partial update operations. In the partial up ...@@ -55,6 +55,8 @@ The `default` is not applied during partial update operations. In the partial up
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). 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).
When serializing the instance, default will be used if the the object attribute or dictionary key is not present in the instance.
Note that setting a `default` value implies that the field is not required. Including both the `default` and `required` keyword arguments is invalid and will raise an error. Note that setting a `default` value implies that the field is not required. Including both the `default` and `required` keyword arguments is invalid and will raise an error.
### `source` ### `source`
......
...@@ -443,7 +443,9 @@ class Field(object): ...@@ -443,7 +443,9 @@ class Field(object):
try: try:
return get_attribute(instance, self.source_attrs) return get_attribute(instance, self.source_attrs)
except (KeyError, AttributeError) as exc: except (KeyError, AttributeError) as exc:
if not self.required and self.default is empty: if self.default is not empty:
return self.get_default()
if not self.required:
raise SkipField() raise SkipField()
msg = ( msg = (
'Got {exc_type} when attempting to get a value for field ' 'Got {exc_type} when attempting to get a value for field '
......
...@@ -372,36 +372,44 @@ class TestNotRequiredOutput: ...@@ -372,36 +372,44 @@ class TestNotRequiredOutput:
serializer.save() serializer.save()
assert serializer.data == {'included': 'abc'} assert serializer.data == {'included': 'abc'}
def test_default_required_output_for_dict(self):
"""
'default="something"' should require dictionary key.
We need to handle this as the field will have an implicit class TestDefaultOutput:
'required=False', but it should still have a value. def setup(self):
"""
class ExampleSerializer(serializers.Serializer): class ExampleSerializer(serializers.Serializer):
omitted = serializers.CharField(default='abc') has_default = serializers.CharField(default='x')
included = serializers.CharField() has_default_callable = serializers.CharField(default=lambda: 'y')
no_default = serializers.CharField()
self.Serializer = ExampleSerializer
serializer = ExampleSerializer({'included': 'abc'}) def test_default_used_for_dict(self):
with pytest.raises(KeyError): """
serializer.data 'default="something"' should be used if dictionary key is missing from input.
"""
serializer = self.Serializer({'no_default': 'abc'})
assert serializer.data == {'has_default': 'x', 'has_default_callable': 'y', 'no_default': 'abc'}
def test_default_required_output_for_object(self): def test_default_used_for_object(self):
""" """
'default="something"' should require object attribute. 'default="something"' should be used if object attribute is missing from input.
"""
instance = MockObject(no_default='abc')
serializer = self.Serializer(instance)
assert serializer.data == {'has_default': 'x', 'has_default_callable': 'y', 'no_default': 'abc'}
We need to handle this as the field will have an implicit def test_default_not_used_when_in_dict(self):
'required=False', but it should still have a value.
""" """
class ExampleSerializer(serializers.Serializer): 'default="something"' should not be used if dictionary key is present in input.
omitted = serializers.CharField(default='abc') """
included = serializers.CharField() serializer = self.Serializer({'has_default': 'def', 'has_default_callable': 'ghi', 'no_default': 'abc'})
assert serializer.data == {'has_default': 'def', 'has_default_callable': 'ghi', 'no_default': 'abc'}
instance = MockObject(included='abc') def test_default_not_used_when_in_object(self):
serializer = ExampleSerializer(instance) """
with pytest.raises(AttributeError): 'default="something"' should not be used if object attribute is present in input.
serializer.data """
instance = MockObject(has_default='def', has_default_callable='ghi', no_default='abc')
serializer = self.Serializer(instance)
assert serializer.data == {'has_default': 'def', 'has_default_callable': 'ghi', 'no_default': 'abc'}
class TestCacheSerializerData: class TestCacheSerializerData:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment