Opened 3 years ago

Closed 3 years ago

#27369 closed Bug (fixed)

Multiple form fields can share the same widget instance

Reported by: Michal Petrucha Owned by: Michal Petrucha
Component: Forms Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Say we have a custom form field that defines a certain HTML class on its widget:

class CustomChoiceField(ChoiceField):
    widget = Select(attrs={'class': 'my-custom-class'})

If this field type is used for multiple fields in the same form, they will all share the same widget instance. This leads to conflicts when setting the fields' choices; since they all use the same widget instance, all fields will render the same choices from the widget even though the fields themselves might have different choices. The following test case fails, for example:

class TestForm(Form):
    field1 = CustomChoiceField(choices=[])
    field2 = CustomChoiceField(choices=[])

f = TestForm()
f.fields['field1'].choices = [("1", "1")]
f.fields['field2'].choices = [("2", "2")]
assert f.fields['field1'].widget.choices == [("1", "1")]
assert f.fields['field2'].widget.choices == [("2", "2")]

I took a deep dive, and found out that since the field instances themselves share the widget instance (as it's a class attribute that doesn't need to get instantiated in each field instance), when fields are getting deepcopied in BaseForm.__init__, their copies all share one new copy of the widget instance.

This is quite easy to fix by deepcopying the widget in the case where it was specified as an instance, rather than a widget class. Patch coming up in a couple of minutes.

Change History (4)

comment:1 Changed 3 years ago by Michal Petrucha

Has patch: set
Last edited 3 years ago by Tim Graham (previous) (diff)

comment:2 Changed 3 years ago by Tim Graham

Triage Stage: UnreviewedAccepted

comment:3 Changed 3 years ago by Tim Graham

Triage Stage: AcceptedReady for checkin

comment:4 Changed 3 years ago by Tim Graham <timograham@…>

Resolution: fixed
Status: assignedclosed

In 09da1e79:

Fixed #27369 -- Prevented widgets from being shared between form field instances.

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