diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 7c48c621e..9c1dbbf64 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1265,14 +1265,13 @@ class MultipleChoiceField(ChoiceField): super(MultipleChoiceField, self).__init__(*args, **kwargs) def get_value(self, dictionary): + if self.field_name not in dictionary: + if getattr(self.root, 'partial', False): + return empty # We override the default field access in order to support # lists in HTML forms. if html.is_html_input(dictionary): - ret = dictionary.getlist(self.field_name) - if getattr(self.root, 'partial', False) and not ret: - ret = empty - return ret - + return dictionary.getlist(self.field_name) return dictionary.get(self.field_name, empty) def to_internal_value(self, data): @@ -1419,6 +1418,9 @@ class ListField(Field): self.child.bind(field_name='', parent=self) def get_value(self, dictionary): + if self.field_name not in dictionary: + if getattr(self.root, 'partial', False): + return empty # We override the default field access in order to support # lists in HTML forms. if html.is_html_input(dictionary): diff --git a/tests/test_serializer_lists.py b/tests/test_serializer_lists.py index e9234d8f7..607ddba04 100644 --- a/tests/test_serializer_lists.py +++ b/tests/test_serializer_lists.py @@ -289,3 +289,32 @@ class TestListSerializerClass: serializer = TestSerializer(data=[], many=True) assert not serializer.is_valid() assert serializer.errors == {'non_field_errors': ['Non field error']} + + +class TestSerializerPartialUsage: + """ + When not submitting key for list fields or multiple choice, partial + serialization should result in an empty state (key not there), not + an empty list. + + Regression test for Github issue #2761. + """ + def test_partial_listfield(self): + class ListSerializer(serializers.Serializer): + listdata = serializers.ListField() + serializer = ListSerializer(data=MultiValueDict(), partial=True) + result = serializer.to_internal_value(data={}) + assert "listdata" not in result + assert serializer.is_valid() + assert serializer.validated_data == {} + assert serializer.errors == {} + + def test_partial_multiplechoice(self): + class MultipleChoiceSerializer(serializers.Serializer): + multiplechoice = serializers.MultipleChoiceField(choices=[1, 2, 3]) + serializer = MultipleChoiceSerializer(data=MultiValueDict(), partial=True) + result = serializer.to_internal_value(data={}) + assert "multiplechoice" not in result + assert serializer.is_valid() + assert serializer.validated_data == {} + assert serializer.errors == {}