Opened 10 years ago

Closed 8 years ago

#21332 closed Cleanup/optimization (fixed)

BaseInlineFormSet.add_fields adds multiple InlineForeignKeyFields

Reported by: Raumkraut Owned by: nobody
Component: Forms Version: 1.6-beta-1
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

When a formset object has its forms iterated over, the _construct_form(...) method calls self.add_fields(...) against each form in the set.

However, for a BaseInlineFormSet, the add_fields implementation creates an InlineForeignKeyField, and appends it to form._meta.fields. It does this for each form, and since form._meta is a class attribute, it ends up with multiple duplicate InlineForeignKeyField instances.

This doesn't appear to be normally evidenced in any usual output, since all the generated FK fields have the same name, so overwrite each other in name-keyed dictionaries of the fields.

Tested on the latest stable/1.6.x branch

Change History (8)

in reply to:  description comment:1 by Raumkraut, 10 years ago

Also note that, unless I'm mistaken, the InlineForeignKeyField instances will continue to be appended to _meta.fields for as long as the server is running, and formsets are being iterated over. Which would make this something of a memory leak.

comment:2 by Tim Graham, 10 years ago

Do you have any ideas to address this? Could you provide a sample project that demonstrates the problem?

comment:3 by Raumkraut, 10 years ago

Okay, so I was wrong about what was getting appended to _meta.fields: It's not InlineForeignKeyField instances which get added, it's only the name of the foreign-key field.

I've cooked up a basic project to demonstrate the issue:
https://github.com/Raumkraut/test_formsets
It should be enough to clone, syncdb and runserver. The root page demonstrates the issue in question.

Since it is just the name of the field which gets appended repeatedly, unless I've missed something, it seems a fix could be fairly simple:

diff --git a/django/forms/models.py b/django/forms/models.py
index 71da433..20a3d54 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -893,7 +893,7 @@ class BaseInlineFormSet(BaseModelFormSet):
 
         # Add the generated field to form._meta.fields if it's defined to make
         # sure validation isn't skipped on that field.
-        if form._meta.fields:
+        if form._meta.fields and self.fk.name not in form._meta.fields:
             if isinstance(form._meta.fields, tuple):
                 form._meta.fields = list(form._meta.fields)
             form._meta.fields.append(self.fk.name)

comment:4 by Anssi Kääriäinen, 10 years ago

Triage Stage: UnreviewedAccepted

I can reproduce, on 1.5.x, 1.6.x and master. The project doesn't seem to be doing anything special.

comment:5 by Carl Meyer, 10 years ago

Type: UncategorizedCleanup/optimization

comment:6 by Tim Graham, 8 years ago

Has patch: set

#26537 is a duplicate with a PR.

comment:7 by Tim Graham, 8 years ago

Triage Stage: AcceptedReady for checkin

comment:8 by Tim Graham <timograham@…>, 8 years ago

Resolution: fixed
Status: newclosed

In a5c8a6ce:

Fixed #21332, #26538 -- Fixed inconsistent and duplicate form fields on inline formsets.

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