diff --git a/django/forms/fields.py b/django/forms/fields.py index 03cd8af8d7..36ec634929 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -199,6 +199,7 @@ class Field: result = copy.copy(self) memo[id(self)] = result result.widget = copy.deepcopy(self.widget, memo) + result.error_messages = self.error_messages.copy() result.validators = self.validators[:] return result diff --git a/tests/forms_tests/field_tests/test_base.py b/tests/forms_tests/field_tests/test_base.py index 4ddbea3414..e789496858 100644 --- a/tests/forms_tests/field_tests/test_base.py +++ b/tests/forms_tests/field_tests/test_base.py @@ -1,3 +1,5 @@ +import copy + from django.forms import ChoiceField, Field, Form, Select from django.test import SimpleTestCase @@ -35,6 +37,56 @@ class BasicFieldsTests(SimpleTestCase): self.assertEqual(f.fields['field1'].widget.choices, [('1', '1')]) self.assertEqual(f.fields['field2'].widget.choices, [('2', '2')]) + def test_field_deepcopies_error_messages(self): + """ + Test that __deepcopy__ creates a deep copy of the error_messages dict. + Modifying error_messages on one field instance should not affect other + instances. + """ + class MyForm(Form): + field1 = Field() + field2 = Field() + + form1 = MyForm() + form2 = MyForm() + + # Store original error message + original_error = str(form2.fields['field1'].error_messages['required']) + + # Modify error_messages on form1's field1 + form1.fields['field1'].error_messages['required'] = 'Custom error for form1' + + # form2's field1 should not be affected + self.assertEqual( + form2.fields['field1'].error_messages['required'], + original_error + ) + + # form1's field2 should not be affected either + self.assertEqual( + form1.fields['field2'].error_messages['required'], + original_error + ) + + # Adding a new error message to form1's field1 should not affect form2 + form1.fields['field1'].error_messages['custom'] = 'New custom error' + self.assertNotIn('custom', form2.fields['field1'].error_messages) + + def test_field_direct_deepcopy_error_messages(self): + """ + Test that directly deepcopying a field creates independent error_messages. + """ + field1 = Field(error_messages={'required': 'Original required error'}) + field2 = copy.deepcopy(field1) + + # Modify field1's error_messages + field1.error_messages['required'] = 'Modified required error' + field1.error_messages['new_error'] = 'A new error' + + # field2 should not be affected + self.assertEqual(field2.error_messages['required'], 'Original required error') + self.assertNotIn('new_error', field2.error_messages) + class DisabledFieldTests(SimpleTestCase): def test_disabled_field_has_changed_always_false(self):