From 8b7ea2bcdd7297941ca6beb72d93b9568e187349 Mon Sep 17 00:00:00 2001 From: afenoum Date: Thu, 26 Mar 2026 11:30:02 +0300 Subject: [PATCH] Refs #36913 -- Maintained error message determinism in MultipleChoiceField.validate(). Used Django's OrderedSet datastructure instead of set() in MultipleChoiceField.validate() to prevent submission ordering from being discarded during validation. Thanks to Jacob Walls, JaeHyuck Sa, Jake Howard and Simon Charette for the reviews. --- django/forms/fields.py | 5 +++-- tests/forms_tests/field_tests/test_multiplechoicefield.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/django/forms/fields.py b/django/forms/fields.py index 7f978aa03d62..8aad2d48b832 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -40,6 +40,7 @@ ) from django.utils import formats from django.utils.choices import normalize_choices +from django.utils.datastructures import OrderedSet from django.utils.dateparse import parse_datetime, parse_duration from django.utils.duration import duration_string from django.utils.ipv6 import MAX_IPV6_ADDRESS_LENGTH, clean_ipv6_address @@ -965,8 +966,8 @@ def validate(self, value): if self.required and not value: raise ValidationError(self.error_messages["required"], code="required") # Validate that each value in the value list is in self.choices. - # Use set() to avoid redundant validation. - for val in set(value): + # Avoid redundant validation, and keep elements ordered. + for val in OrderedSet(value): if not self.valid_value(val): raise ValidationError( self.error_messages["invalid_choice"], diff --git a/tests/forms_tests/field_tests/test_multiplechoicefield.py b/tests/forms_tests/field_tests/test_multiplechoicefield.py index 90a47ceee021..0ec53e1b30f4 100644 --- a/tests/forms_tests/field_tests/test_multiplechoicefield.py +++ b/tests/forms_tests/field_tests/test_multiplechoicefield.py @@ -91,5 +91,5 @@ def test_validate_duplicated_values(self): def test_validate_duplicated_invalid_values(self): f = MultipleChoiceField(choices=[("1", "one"), ("2", "Two")]) - with self.assertRaises(ValidationError): - f.validate(["1", "1", "invalid", "invalid"]) + with self.assertRaisesMessage(ValidationError, "invalid-one"): + f.validate(["invalid-one", "invalid-one", "invalid-two"])