Code

Opened 2 years ago

Closed 22 months ago

#17981 closed Bug (duplicate)

attr property unexpectedly shared between widgets in MultiWidget

Reported by: supervacuo Owned by: nobody
Component: Forms Version: 1.4
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

I have encountered the following method for making a widget that's just an existing widget with a custom class (from the django-bootstrap-toolkit project):

class FooWidget(forms.TextInput):                                               
  def render(self, name, value, attrs=None):                                    
    if not attrs:                                                               
      attrs = {}                                                                
    attrs['class'] = 'flibble'                                                  
    return super(FooWidget, self).render(name, value, attrs)

(code to only add class conditionally omitted for clarity).

I tried adding such a widget to another custom widget, based on MultiWidget:

class BarWidget(forms.MultiWidget):                          
  def __init__(self):
    widgets = (
      FooWidget(),                                                              
      forms.TextInput(),)                   
    super(BarWidget, self).__init__(widgets, None)           

but in the output, both widgets are rendered with class = 'flibble'. If the order of widgets reversed, only FooWidget has the applied class, as expected.

I can't see anything in the definition of MultiWidget which immediately explains this. Thoughts?

This is not a duplicate of #5851 (as far as I can tell).

Attachments (0)

Change History (2)

comment:1 Changed 2 years ago by koenb

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

This is actually a bug in your code, not in django's. You are modifying the attrs object in your render method. Remember that objects are passed into functions by reference in python, so if the multiwidget passes a dict into the render method, you are changing that dict inside your method, not a copy.

This is actually an easy mistake to make, so we may be able to protect against this in the multiwidget code. The patch I added to #5851 for instance does not have this problem anymore, since it passes a different dict into the different render methods.

Not sure whether I should leave this open?

comment:2 Changed 22 months ago by jezdez

  • Resolution set to duplicate
  • Status changed from new to closed

Yeah, this is just a duplicate of #5851.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.