Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,12 @@ def validate_empty_values(self, data):
raise SkipField()
if self.required:
self.fail('required')
return (True, self.get_default())
try:
return (True, self.get_default())
except SkipField:
if self.allow_null:
return (True, None)
raise

if data is None:
if not self.allow_null:
Expand Down
89 changes: 89 additions & 0 deletions tests/test_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,95 @@ def test_default_should_not_be_included_on_partial_update(self):
assert serializer.errors == {}


class TestAllowNullNotRequiredInclusions:
"""
Test that allow_null=True, required=False fields are included in
validated_data as None when partial=False. Refs #9501.
"""

def test_allow_null_not_required_missing_field_included_on_create(self):
class ExampleSerializer(serializers.Serializer):
name = serializers.CharField()
nullable_field = serializers.CharField(
required=False, allow_null=True
)

serializer = ExampleSerializer(data={'name': 'test'})
assert serializer.is_valid()
assert serializer.validated_data == {
'name': 'test',
'nullable_field': None,
}

def test_allow_null_not_required_missing_field_included_on_update(self):
class ExampleSerializer(serializers.Serializer):
name = serializers.CharField()
nullable_field = serializers.CharField(
required=False, allow_null=True
)

instance = MockObject(name='old', nullable_field='old_value')
serializer = ExampleSerializer(instance, data={'name': 'test'})
assert serializer.is_valid()
assert serializer.validated_data == {
'name': 'test',
'nullable_field': None,
}

def test_allow_null_not_required_missing_field_skipped_on_partial_update(self):
class ExampleSerializer(serializers.Serializer):
name = serializers.CharField()
nullable_field = serializers.CharField(
required=False, allow_null=True
)

instance = MockObject(name='old', nullable_field='old_value')
serializer = ExampleSerializer(
instance, data={'name': 'test'}, partial=True
)
assert serializer.is_valid()
assert serializer.validated_data == {'name': 'test'}

def test_allow_null_not_required_explicit_null_still_works(self):
class ExampleSerializer(serializers.Serializer):
name = serializers.CharField()
nullable_field = serializers.CharField(
required=False, allow_null=True
)

serializer = ExampleSerializer(
data={'name': 'test', 'nullable_field': None}
)
assert serializer.is_valid()
assert serializer.validated_data == {
'name': 'test',
'nullable_field': None,
}

def test_allow_null_not_required_with_explicit_default(self):
class ExampleSerializer(serializers.Serializer):
name = serializers.CharField()
nullable_field = serializers.CharField(
required=False, allow_null=True, default='fallback'
)

serializer = ExampleSerializer(data={'name': 'test'})
assert serializer.is_valid()
assert serializer.validated_data == {
'name': 'test',
'nullable_field': 'fallback',
}

def test_not_required_without_allow_null_still_skipped(self):
class ExampleSerializer(serializers.Serializer):
name = serializers.CharField()
optional_field = serializers.CharField(required=False)

serializer = ExampleSerializer(data={'name': 'test'})
assert serializer.is_valid()
assert serializer.validated_data == {'name': 'test'}


class TestSerializerValidationWithCompiledRegexField:
def setup_method(self):
class ExampleSerializer(serializers.Serializer):
Expand Down