mirror of
https://github.com/django/django.git
synced 2025-11-20 11:36:04 +00:00
Fix field deepcopy to copy error_messages dict
Ensure Field.__deepcopy__ creates an independent copy of error_messages. Prevents changes to error messages in one form field instance from affecting others. Addresses shared mutable error_messages issue (#issue).
This commit is contained in:
parent
06909fe084
commit
2f38240802
2 changed files with 53 additions and 0 deletions
|
|
@ -199,6 +199,7 @@ class Field:
|
||||||
result = copy.copy(self)
|
result = copy.copy(self)
|
||||||
memo[id(self)] = result
|
memo[id(self)] = result
|
||||||
result.widget = copy.deepcopy(self.widget, memo)
|
result.widget = copy.deepcopy(self.widget, memo)
|
||||||
|
result.error_messages = self.error_messages.copy()
|
||||||
result.validators = self.validators[:]
|
result.validators = self.validators[:]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import copy
|
||||||
|
|
||||||
from django.forms import ChoiceField, Field, Form, Select
|
from django.forms import ChoiceField, Field, Form, Select
|
||||||
from django.test import SimpleTestCase
|
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['field1'].widget.choices, [('1', '1')])
|
||||||
self.assertEqual(f.fields['field2'].widget.choices, [('2', '2')])
|
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):
|
class DisabledFieldTests(SimpleTestCase):
|
||||||
def test_disabled_field_has_changed_always_false(self):
|
def test_disabled_field_has_changed_always_false(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue