Opened 15 years ago

Last modified 9 years 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
Pull Requests:How to create a pull request

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.

According to the ticket's flags, the next step(s) to move this issue forward are:

  • To provide a patch by sending a pull request. Claim the ticket when you start working so that someone else doesn't duplicate effort. Before sending a pull request, review your work against the patch review checklist. Check the "Has patch" flag on the ticket after sending a pull request and include a link to the pull request in the ticket comment when making that update. The usual format is: [https://github.com/django/django/pull/#### PR].

Change History (7)

by James Bennett, 15 years ago

Attachment: 12134.diff added

comment:1 by Brian Rosner, 15 years ago

Triage Stage: UnreviewedAccepted

comment:2 by Luke Plant, 15 years ago

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 by Matt McClanahan, 14 years ago

Severity: Normal
Type: Bug

comment:4 by Aymeric Augustin, 13 years ago

UI/UX: unset

Change UI/UX from NULL to False.

comment:5 by Aymeric Augustin, 13 years ago

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:6 by Tim Graham, 9 years ago

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