From d0b85b28b78f7fe97cfb0a90046788b649ab5326 Mon Sep 17 00:00:00 2001 From: Jamie Cockburn Date: Fri, 27 Oct 2017 12:55:25 +0100 Subject: [PATCH] Pass correct initial_data to ListSerializer child (#5345) --- rest_framework/serializers.py | 18 ++++++++-- tests/test_serializer_lists.py | 64 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 59533be1e5..9041af571c 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -631,6 +631,7 @@ def to_internal_value(self, data): errors = [] for item in data: + self.child.initial_data = item try: validated = self.child.run_validation(item) except ValidationError as exc: @@ -669,9 +670,20 @@ def update(self, instance, validated_data): ) def create(self, validated_data): - return [ - self.child.create(attrs) for attrs in validated_data - ] + ret = [] + if hasattr(self, 'initial_data'): + initial_data = self.initial_data + if html.is_html_input(initial_data): + initial_data = html.parse_html_list(initial_data) + else: + initial_data = None + + for i, attrs in enumerate(validated_data): + if initial_data is not None: + self.child.initial_data = initial_data[i] + ret.append(self.child.create(attrs)) + + return ret def save(self, **kwargs): """ diff --git a/tests/test_serializer_lists.py b/tests/test_serializer_lists.py index a7955d83c7..6706695ab5 100644 --- a/tests/test_serializer_lists.py +++ b/tests/test_serializer_lists.py @@ -138,6 +138,70 @@ def test_validate_html_input(self): assert serializer.is_valid() assert serializer.validated_data == expected_output + def test_validate_initial_data(self): + data = [{"field": "value1"}, {"field": "value2"}] + expected_initial_data = list(data) + + class AssertingChildSerializer(serializers.Serializer): + def validate(self, attrs): + assert self.initial_data == expected_initial_data.pop(0) + return attrs + + serializer = AssertingChildSerializer(data=list(data), many=True) + assert serializer.is_valid() + assert len(expected_initial_data) == 0 + + def test_create_initial_data(self): + data = [{"field": "value1"}, {"field": "value2"}] + expected_initial_data = list(data) + + class AssertingChildSerializer(serializers.Serializer): + field = serializers.CharField() + + def create(self, validated_data): + assert self.initial_data == expected_initial_data.pop(0) + return validated_data + + serializer = AssertingChildSerializer(data=data, many=True) + assert serializer.is_valid() + assert serializer.save() == data + assert len(expected_initial_data) == 0 + + def test_validate_initial_data_html_input(self): + expected_initial_data = [{"field": ["value1"]}, {"field": ["value2"]}] + + class AssertingChildSerializer(serializers.Serializer): + def validate(self, attrs): + assert self.initial_data == expected_initial_data.pop(0) + return attrs + + initial_data = MultiValueDict({ + "[0]field": ["value1"], + "[1]field": ["value2"], + }) + serializer = AssertingChildSerializer(data=initial_data, many=True) + assert serializer.is_valid() + assert len(expected_initial_data) == 0 + + def test_create_initial_data_html_input(self): + expected_initial_data = [{"field": ["value1"]}, {"field": ["value2"]}] + + class AssertingChildSerializer(serializers.Serializer): + field = serializers.CharField() + + def create(self, validated_data): + assert self.initial_data == expected_initial_data.pop(0) + return validated_data + + initial_data = MultiValueDict({ + "[0]field": ["value1"], + "[1]field": ["value2"], + }) + serializer = AssertingChildSerializer(data=initial_data, many=True) + assert serializer.is_valid() + assert serializer.save() == [{"field": "value1"}, {"field": "value2"}] + assert len(expected_initial_data) == 0 + class TestNestedListSerializer: """