Enforce allow_empty=False during partial validation of parent serializer (#6512)

Refs #6509

This enforces allow_empty=True when a ListSerializer is a child of another serializer and partial validation is being performed on the parent serializer.

This is because partial validation should allow fields to be omitted, but should not cause values that are invalid without partial validation to become valid.

This effectively reverts #4222. None of the tests added in that PR fail if the associated change is removed, so I‘m not sure what that PR was trying to fix.
This commit is contained in:
Reupen Shah 2019-07-01 13:30:16 +01:00 committed by Tom Christie
parent 79b2350b54
commit 3242adf058
2 changed files with 45 additions and 7 deletions

View File

@ -590,10 +590,6 @@ class ListSerializer(BaseSerializer):
super().__init__(*args, **kwargs)
self.child.bind(field_name='', parent=self)
def bind(self, field_name, parent):
super().bind(field_name, parent)
self.partial = self.parent.partial
def get_initial(self):
if hasattr(self, 'initial_data'):
return self.to_representation(self.initial_data)
@ -645,9 +641,6 @@ class ListSerializer(BaseSerializer):
}, code='not_a_list')
if not self.allow_empty and len(data) == 0:
if self.parent and self.partial:
raise SkipField()
message = self.error_messages['empty']
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]

View File

@ -1,7 +1,9 @@
import pytest
from django.http import QueryDict
from django.utils.datastructures import MultiValueDict
from rest_framework import serializers
from rest_framework.exceptions import ErrorDetail
class BasicObject:
@ -223,6 +225,49 @@ class TestNestedListSerializer:
assert serializer.validated_data == expected_output
class TestNestedListSerializerAllowEmpty:
"""Tests the behaviour of allow_empty=False when a ListSerializer is used as a field."""
@pytest.mark.parametrize('partial', (False, True))
def test_allow_empty_true(self, partial):
"""
If allow_empty is True, empty lists should be allowed regardless of the value
of partial on the parent serializer.
"""
class ChildSerializer(serializers.Serializer):
id = serializers.IntegerField()
class ParentSerializer(serializers.Serializer):
ids = ChildSerializer(many=True, allow_empty=True)
serializer = ParentSerializer(data={'ids': []}, partial=partial)
assert serializer.is_valid()
assert serializer.validated_data == {
'ids': [],
}
@pytest.mark.parametrize('partial', (False, True))
def test_allow_empty_false(self, partial):
"""
If allow_empty is False, empty lists should fail validation regardless of the value
of partial on the parent serializer.
"""
class ChildSerializer(serializers.Serializer):
id = serializers.IntegerField()
class ParentSerializer(serializers.Serializer):
ids = ChildSerializer(many=True, allow_empty=False)
serializer = ParentSerializer(data={'ids': []}, partial=partial)
assert not serializer.is_valid()
assert serializer.errors == {
'ids': {
'non_field_errors': [
ErrorDetail(string='This list may not be empty.', code='empty')],
}
}
class TestNestedListOfListsSerializer:
def setup(self):
class TestSerializer(serializers.Serializer):