aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Christie2015-01-05 15:04:23 +0000
committerTom Christie2015-01-05 15:04:23 +0000
commit949e3b7507ee4e7b0c571cb6a7eba076dee91a38 (patch)
treedadb26c5c8c40b2aaafad85608470e50c10c1370
parent49dc037a961b618baf8eb189b094633238867b41 (diff)
parent6fd33ddea9e5b8f9e979e573a27873131846ea48 (diff)
downloaddjango-rest-framework-949e3b7507ee4e7b0c571cb6a7eba076dee91a38.tar.bz2
Merge branch 'master' into version-3.1
-rw-r--r--docs/api-guide/fields.md2
-rw-r--r--rest_framework/fields.py2
-rw-r--r--rest_framework/serializers.py8
-rw-r--r--tests/test_serializer.py62
4 files changed, 73 insertions, 1 deletions
diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md
index 946e355d..b3d274dd 100644
--- a/docs/api-guide/fields.md
+++ b/docs/api-guide/fields.md
@@ -41,6 +41,8 @@ Defaults to `False`
Normally an error will be raised if a field is not supplied during deserialization.
Set to false if this field is not required to be present during deserialization.
+Setting this to `False` also allows the object attribute or dictionary key to be omitted from output when serializing the instance. If the key is not present it will simply not be included in the output representation.
+
Defaults to `True`.
### `allow_null`
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index aab80982..cc9410aa 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -288,6 +288,8 @@ class Field(object):
try:
return get_attribute(instance, self.source_attrs)
except (KeyError, AttributeError) as exc:
+ if not self.required and self.default is empty:
+ raise SkipField()
msg = (
'Got {exc_type} when attempting to get a value for field '
'`{field}` on serializer `{serializer}`.\nThe serializer '
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 08a58433..d1bd3ec3 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -421,8 +421,14 @@ class Serializer(BaseSerializer):
fields = [field for field in self.fields.values() if not field.write_only]
for field in fields:
- attribute = field.get_attribute(instance)
+ try:
+ attribute = field.get_attribute(instance)
+ except SkipField:
+ continue
+
if attribute is None:
+ # We skip `to_representation` for `None` values so that
+ # fields do not have to explicitly deal with that case.
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
diff --git a/tests/test_serializer.py b/tests/test_serializer.py
index c17b6d8c..68bbbe98 100644
--- a/tests/test_serializer.py
+++ b/tests/test_serializer.py
@@ -1,5 +1,6 @@
# coding: utf-8
from __future__ import unicode_literals
+from .utils import MockObject
from rest_framework import serializers
from rest_framework.compat import unicode_repr
import pytest
@@ -216,3 +217,64 @@ class TestUnicodeRepr:
instance = ExampleObject()
serializer = ExampleSerializer(instance)
repr(serializer) # Should not error.
+
+
+class TestNotRequiredOutput:
+ def test_not_required_output_for_dict(self):
+ """
+ 'required=False' should allow a dictionary key to be missing in output.
+ """
+ class ExampleSerializer(serializers.Serializer):
+ omitted = serializers.CharField(required=False)
+ included = serializers.CharField()
+
+ serializer = ExampleSerializer(data={'included': 'abc'})
+ serializer.is_valid()
+ assert serializer.data == {'included': 'abc'}
+
+ def test_not_required_output_for_object(self):
+ """
+ 'required=False' should allow an object attribute to be missing in output.
+ """
+ class ExampleSerializer(serializers.Serializer):
+ omitted = serializers.CharField(required=False)
+ included = serializers.CharField()
+
+ def create(self, validated_data):
+ return MockObject(**validated_data)
+
+ serializer = ExampleSerializer(data={'included': 'abc'})
+ serializer.is_valid()
+ serializer.save()
+ 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
+ 'required=False', but it should still have a value.
+ """
+ class ExampleSerializer(serializers.Serializer):
+ omitted = serializers.CharField(default='abc')
+ included = serializers.CharField()
+
+ serializer = ExampleSerializer({'included': 'abc'})
+ with pytest.raises(KeyError):
+ serializer.data
+
+ def test_default_required_output_for_object(self):
+ """
+ 'default="something"' should require object attribute.
+
+ We need to handle this as the field will have an implicit
+ 'required=False', but it should still have a value.
+ """
+ class ExampleSerializer(serializers.Serializer):
+ omitted = serializers.CharField(default='abc')
+ included = serializers.CharField()
+
+ instance = MockObject(included='abc')
+ serializer = ExampleSerializer(instance)
+ with pytest.raises(AttributeError):
+ serializer.data