#12048 closed (fixed)
MultiWidget does not define __deepcopy__
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Forms | Version: | dev |
Severity: | Keywords: | ||
Cc: | ben@… | Triage Stage: | Design decision needed |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
django.forms.MultiWidget defines an instance variable, widgets
, which is a list of widgets. However, it does not override the deepcopy() method in the Widget base class to make a copy of this instance variable. A deepcopy of the widgets is needed when an instance when a django Form containing a Field that uses a MultiWidget is instantiated, otherwise all such forms have a reference to the same widgets list rather than their own copy.
The patch is simple - override deepcopy() in MultiWidget to make a copy of widgets. A proposed patch is attached.
Replicating the problem requires that we extend MultiWidget, make a deepcopy of the widget, then alter one of the widgets in some way. Here is a minimal example that demonstrates the issue - applying the patch fixes the issue.
from django import forms from django.utils.encoding import StrAndUnicode, force_unicode from django.utils.safestring import mark_safe ##################################################### ## Simplified ChoiceWithOtherWidget ## original downloaded from: http://www.djangosnippets.org/snippets/863/ ##################################################### class ChoiceWithOtherWidget(forms.MultiWidget): """MultiWidget for use with ChoiceWithOtherField.""" def __init__(self, choices=[]): widgets = [ forms.RadioSelect(choices=choices), forms.TextInput ] super(ChoiceWithOtherWidget, self).__init__(widgets) def _set_choices(self, choices): """ When choices are set for this widget, we want to pass those along to the Select widget""" self.widgets[0].choices = choices def _get_choices(self): """ The choices for this widget are the Select widget's choices""" return self.widgets[0].choices choices = property(_get_choices, _set_choices) def decompress(self, value): if not value: return [None, None] return value ################################################# ## Minimal code to reproduces bug ################################################# from copy import deepcopy widget1 = ChoiceWithOtherWidget(choices=['A','B','C']) widget2 = deepcopy(widget1) widget2.choices=['X','Y','Z'] widget1.choices widget2.choices
Here is the output from running the sample code above in a shell before the patch was applied:
>>> widget1 = ChoiceWithOtherWidget(choices=['A','B','C']) >>> widget2 = deepcopy(widget1) >>> widget2.choices=['X','Y','Z'] >>> >>> widget1.choices ['X', 'Y', 'Z'] >>> widget2.choices ['X', 'Y', 'Z']
... and after the patch was applied:
>>> widget1 = ChoiceWithOtherWidget(choices=['A','B','C']) >>> widget2 = deepcopy(widget1) >>> widget2.choices=['X','Y','Z'] >>> >>> widget1.choices ['A', 'B', 'C'] >>> widget2.choices ['X', 'Y', 'Z']
Attachments (1)
Change History (6)
by , 15 years ago
Attachment: | widgets.py.patch added |
---|
comment:1 by , 15 years ago
Cc: | added |
---|
comment:2 by , 15 years ago
Triage Stage: | Unreviewed → Design decision needed |
---|
comment:3 by , 15 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
patch for MultiWidget deepcopy bug (django.forms.MultiWidget)