From fdde44d9d1de7299a06fe618a98a5068a806e491 Mon Sep 17 00:00:00 2001 From: Laurent De Marez Date: Thu, 23 Jun 2016 17:03:24 +0200 Subject: [PATCH] Fix parsing multipart data using a nested serializer with list (#3820) It is possible that a key in a MultiValueDict has multiple values, lists are represented this way. When accessing a key in a MultiValueDict it only returns the last element of that key. This becomes a problem when parsing an html dict with a list inside of it. To fix this problem we have to get and set the value using .getlist() and .setlist(). --- rest_framework/utils/html.py | 6 ++++-- tests/test_serializer_nested.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/rest_framework/utils/html.py b/rest_framework/utils/html.py index 3b871027c7..121c825c73 100644 --- a/rest_framework/utils/html.py +++ b/rest_framework/utils/html.py @@ -80,10 +80,12 @@ def parse_html_dict(dictionary, prefix=''): """ ret = MultiValueDict() regex = re.compile(r'^%s\.(.+)$' % re.escape(prefix)) - for field, value in dictionary.items(): + for field in dictionary: match = regex.match(field) if not match: continue key = match.groups()[0] - ret[key] = value + value = dictionary.getlist(field) + ret.setlist(key, value) + return ret diff --git a/tests/test_serializer_nested.py b/tests/test_serializer_nested.py index aeb092ee05..1336003995 100644 --- a/tests/test_serializer_nested.py +++ b/tests/test_serializer_nested.py @@ -167,3 +167,32 @@ def test_empty_not_allowed_if_allow_empty_is_set_to_false(self): expected_errors = {'not_allow_empty': {'non_field_errors': [serializers.ListSerializer.default_error_messages['empty']]}} assert serializer.errors == expected_errors + + +class TestNestedSerializerWithList: + def setup(self): + class NestedSerializer(serializers.Serializer): + example = serializers.MultipleChoiceField(choices=[1, 2, 3]) + + class TestSerializer(serializers.Serializer): + nested = NestedSerializer() + + self.Serializer = TestSerializer + + def test_nested_serializer_with_list_json(self): + input_data = { + 'nested': { + 'example': [1, 2], + } + } + serializer = self.Serializer(data=input_data) + + assert serializer.is_valid() + assert serializer.validated_data['nested']['example'] == set([1, 2]) + + def test_nested_serializer_with_list_multipart(self): + input_data = QueryDict('nested.example=1&nested.example=2') + serializer = self.Serializer(data=input_data) + + assert serializer.is_valid() + assert serializer.validated_data['nested']['example'] == set([1, 2])