From 1544fafcb88029c7df30c3df89a326407c58f0e9 Mon Sep 17 00:00:00 2001 From: Sezer BOZKIR Date: Wed, 25 Feb 2026 10:08:27 +0300 Subject: [PATCH 01/13] respecting ordered sequence while partial update is fixed --- rest_framework/fields.py | 16 ++++++++++++---- tests/test_serializer_lists.py | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index f5009a7303..7f6195ddd2 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1675,9 +1675,6 @@ def __init__(self, **kwargs): self.validators.append(MinLengthValidator(self.min_length, message=message)) 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): @@ -1685,7 +1682,18 @@ def get_value(self, dictionary): if len(val) > 0: # Support QueryDict lists in HTML input. return val - return html.parse_html_list(dictionary, prefix=self.field_name, default=empty) + # Check for indexed keys like field_name[0], field_name[1], etc. + # before returning empty on partial updates + html_list = html.parse_html_list(dictionary, prefix=self.field_name, default=empty) + if html_list is not empty: + return html_list + # If no HTML list data found and this is a partial update, return empty + if getattr(self.root, 'partial', False): + return empty + return html_list + if self.field_name not in dictionary: + if getattr(self.root, 'partial', False): + return empty return dictionary.get(self.field_name, empty) diff --git a/tests/test_serializer_lists.py b/tests/test_serializer_lists.py index f76451a5ad..ff405cdad4 100644 --- a/tests/test_serializer_lists.py +++ b/tests/test_serializer_lists.py @@ -426,6 +426,28 @@ class MultipleChoiceSerializer(serializers.Serializer): assert serializer.validated_data == {} assert serializer.errors == {} + def test_partial_listfield_with_indexed_keys(self): + """ + Test that ListField respects ordered sequence in form data with partial updates. + Regression test for GitHub issue where indexed keys like field[0], field[1] + were not being parsed in partial updates. + """ + class CommunitySerializer(serializers.Serializer): + colors = serializers.ListField( + allow_null=True, + child=serializers.CharField(label='Colors', max_length=7), + required=False + ) + # Simulate form data with indexed keys + data = MultiValueDict({ + 'colors[0]': ['#ffffff'], + 'colors[1]': ['#000000'] + }) + serializer = CommunitySerializer(data=data, partial=True) + assert serializer.is_valid(), f"Expected valid but got errors: {serializer.errors}" + assert 'colors' in serializer.validated_data + assert serializer.validated_data['colors'] == ['#ffffff', '#000000'] + def test_allow_empty_true(self): class ListSerializer(serializers.Serializer): update_field = serializers.IntegerField() From 9caec6e15b0a539e10a223a5759a70674356eb87 Mon Sep 17 00:00:00 2001 From: Sezer BOZKIR Date: Mon, 2 Mar 2026 12:28:51 +0300 Subject: [PATCH 02/13] getting field order is re-ordered for backward compatibility --- rest_framework/fields.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 220a40cb04..3c47a5e8f7 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1683,19 +1683,26 @@ def get_value(self, dictionary): # We override the default field access in order to support # lists in HTML forms. if html.is_html_input(dictionary): + # First, try to get the value using the plain field name with getlist + # This handles standard HTML form list submissions like: + #