diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 891b250f4..b153c067f 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -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] diff --git a/tests/test_serializer_lists.py b/tests/test_serializer_lists.py index 12ed78b84..98e72385a 100644 --- a/tests/test_serializer_lists.py +++ b/tests/test_serializer_lists.py @@ -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):