Opened 7 years ago

Last modified 10 months ago

#12134 new Bug

contrib.admin.RelatedFieldWidgetWrapper.__deepcopy__() should copy() the widget attrs

Reported by: James Bennett Owned by: nobody
Component: contrib.admin Version: 1.1
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Otherwise it ends up with a shallow copy which reuses the same attrs dict across separate widget instances, playing merry hell with form classes which want to change widget attrs on a per-(form)-instance basis.

Attachments (1)

12134.diff (489 bytes) - added by James Bennett 7 years ago.

Download all attachments as: .zip

Change History (7)

Changed 7 years ago by James Bennett

Attachment: 12134.diff added

comment:1 Changed 7 years ago by Brian Rosner

Triage Stage: UnreviewedAccepted

comment:2 Changed 7 years ago by Luke Plant

I think we need some more analysis of why this patch is correct/needed. Here are some simplified extracts of current code:

class RelatedFieldWidgetWrapper(forms.Widget):
    def __init__(self, widget, rel, admin_site):
        self.attrs = widget.attrs
        self.widget = widget
        # <snip>

    def __deepcopy__(self, memo):
        obj = copy.copy(self)
        obj.widget = copy.deepcopy(self.widget, memo)
        obj.attrs = self.widget.attrs
        memo[id(self)] = obj
        return obj

This means:

wrapper1 = RelatedFieldWidgetWrapper(some_widget, some_rel, some_admin_site)
wrapper2 = copy.deepcopy(wrapper1) # as happens when widget is copied via BaseForm.__init__()

assert wrapper1.attrs is wrapper1.widget.attrs
assert wrapper2.attrs is wrapper2.widget.attrs
assert wrapper1.widget is not wrapper2.widget

That all seems to be correct. The attached patch would actually break the second assert, which I'm pretty sure will break the ability of the class instance to work as a wrapper.

comment:3 Changed 6 years ago by Matt McClanahan

Severity: Normal
Type: Bug

comment:4 Changed 5 years ago by Aymeric Augustin

UI/UX: unset

Change UI/UX from NULL to False.

comment:5 Changed 5 years ago by Aymeric Augustin

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:6 Changed 10 months ago by Tim Graham

I think #26213 gives a demonstration of a behavior which this ticket may fix.

Note: See TracTickets for help on using tickets.
Back to Top