mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-04-27 20:43:46 +03:00
Fix nullable source='*'
fields (#6659)
This commit is contained in:
parent
2c92548963
commit
1b8141a4aa
|
@ -493,6 +493,11 @@ class Field:
|
||||||
if data is None:
|
if data is None:
|
||||||
if not self.allow_null:
|
if not self.allow_null:
|
||||||
self.fail('null')
|
self.fail('null')
|
||||||
|
# Nullable `source='*'` fields should not be skipped when its named
|
||||||
|
# field is given a null value. This is because `source='*'` means
|
||||||
|
# the field is passed the entire object, which is not null.
|
||||||
|
elif self.source == '*':
|
||||||
|
return (False, None)
|
||||||
return (True, None)
|
return (True, None)
|
||||||
|
|
||||||
return (False, data)
|
return (False, data)
|
||||||
|
|
|
@ -317,7 +317,8 @@ class TestBaseSerializer:
|
||||||
|
|
||||||
class TestStarredSource:
|
class TestStarredSource:
|
||||||
"""
|
"""
|
||||||
Tests for `source='*'` argument, which is used for nested representations.
|
Tests for `source='*'` argument, which is often used for complex field or
|
||||||
|
nested representations.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -337,11 +338,28 @@ class TestStarredSource:
|
||||||
c = serializers.IntegerField()
|
c = serializers.IntegerField()
|
||||||
d = serializers.IntegerField()
|
d = serializers.IntegerField()
|
||||||
|
|
||||||
class TestSerializer(serializers.Serializer):
|
class NestedBaseSerializer(serializers.Serializer):
|
||||||
nested1 = NestedSerializer1(source='*')
|
nested1 = NestedSerializer1(source='*')
|
||||||
nested2 = NestedSerializer2(source='*')
|
nested2 = NestedSerializer2(source='*')
|
||||||
|
|
||||||
self.Serializer = TestSerializer
|
# nullable nested serializer testing
|
||||||
|
class NullableNestedSerializer(serializers.Serializer):
|
||||||
|
nested = NestedSerializer1(source='*', allow_null=True)
|
||||||
|
|
||||||
|
# nullable custom field testing
|
||||||
|
class CustomField(serializers.Field):
|
||||||
|
def to_representation(self, instance):
|
||||||
|
return getattr(instance, 'foo', None)
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
return {'foo': data}
|
||||||
|
|
||||||
|
class NullableFieldSerializer(serializers.Serializer):
|
||||||
|
field = CustomField(source='*', allow_null=True)
|
||||||
|
|
||||||
|
self.Serializer = NestedBaseSerializer
|
||||||
|
self.NullableNestedSerializer = NullableNestedSerializer
|
||||||
|
self.NullableFieldSerializer = NullableFieldSerializer
|
||||||
|
|
||||||
def test_nested_validate(self):
|
def test_nested_validate(self):
|
||||||
"""
|
"""
|
||||||
|
@ -356,6 +374,12 @@ class TestStarredSource:
|
||||||
'd': 4
|
'd': 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def test_nested_null_validate(self):
|
||||||
|
serializer = self.NullableNestedSerializer(data={'nested': None})
|
||||||
|
|
||||||
|
# validation should fail (but not error) since nested fields are required
|
||||||
|
assert not serializer.is_valid()
|
||||||
|
|
||||||
def test_nested_serialize(self):
|
def test_nested_serialize(self):
|
||||||
"""
|
"""
|
||||||
An object can be serialized into a nested representation.
|
An object can be serialized into a nested representation.
|
||||||
|
@ -364,6 +388,20 @@ class TestStarredSource:
|
||||||
serializer = self.Serializer(instance)
|
serializer = self.Serializer(instance)
|
||||||
assert serializer.data == self.data
|
assert serializer.data == self.data
|
||||||
|
|
||||||
|
def test_field_validate(self):
|
||||||
|
serializer = self.NullableFieldSerializer(data={'field': 'bar'})
|
||||||
|
|
||||||
|
# validation should pass since no internal validation
|
||||||
|
assert serializer.is_valid()
|
||||||
|
assert serializer.validated_data == {'foo': 'bar'}
|
||||||
|
|
||||||
|
def test_field_null_validate(self):
|
||||||
|
serializer = self.NullableFieldSerializer(data={'field': None})
|
||||||
|
|
||||||
|
# validation should pass since no internal validation
|
||||||
|
assert serializer.is_valid()
|
||||||
|
assert serializer.validated_data == {'foo': None}
|
||||||
|
|
||||||
|
|
||||||
class TestIncorrectlyConfigured:
|
class TestIncorrectlyConfigured:
|
||||||
def test_incorrect_field_name(self):
|
def test_incorrect_field_name(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user