#16995 closed Bug (fixed)
ModelFormSet initial data from initial parameter uses "extra" forms
| Reported by: | Owned by: | Mark Gensler | |
|---|---|---|---|
| Component: | Documentation | Version: | dev |
| 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
It seems that when you feed initial data into a ModelFromSet using the initial parameter, it uses the "extra" forms that you define with the extra parameter in the modelformset_factory. For example, if you feed a list of two dictionaries (with the model data) into the initial parameter of a FormSet, but the formset_factory that the FormSet was created from has an extra parameter of 1 (or None), then only the model data from the first dictionary in the list will show up in the FormSet.
Since "initial" data doen't seem like they should be in the "extra" forms, I think this is a bug?
Change History (8)
comment:1 by , 14 years ago
| Component: | Forms → Documentation |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
| Version: | 1.3 → SVN |
comment:2 by , 14 years ago
I was about to report this as a separate bug (after asking in #django-dev); I see this is as a feature proposal along the lines of "Set extra to the length of initial in ModelFormSet if it is not set manually".
I'm using modelformset_factory to create a model formset class, then passing initial in the constructor when instantiating it. Line 91 of forms/formsets.py uses the value of extra to work out how many extra forms should be drawn, but I think this information could already be implied by the length of the initial dict, at least in the case where extra is not specified (for backwards compatibility), and having to specify both seems a little like Repeating Yourself.
The code I'm using which demonstrates the problem is here.
I can certainly try writing a patch (it shouldn't be a big change, and I imagine the tests would be pretty straightforward) if this seems like a good idea. If not, I agree that the "Making forms from models" docs should explain that extra needs to be set, even with initial, using something like
from django.forms.models import modelformset_factory foos = some_function_that_returns_a_list_of_foo() FooFormSet = modelformset_factory(Foo, extra=len(foos)) foo_formset = FooFormSet(initial=[f.__dict__ for f in foos])
comment:3 by , 12 years ago
The quick workaround on this is to use lambda function:
from django.forms.models import modelformset_factory
foos = some_function_that_returns_a_list_of_foo()
FooFormSet = lambda *args, **kwargs: modelformset_factory(Foo, extra=kwargs.pop('extra', 0))(*args, **kwargs)
foo_formset = FooFormSet(initial=[f.__dict__ for f in foos], extra=len(foos))
comment:4 by , 7 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
I will work on adding this to the documentation.
comment:5 by , 7 years ago
| Has patch: | set |
|---|
Patch and pull request created at https://github.com/django/django/pull/10372
comment:6 by , 7 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
I believe this is working as designed. I do, however, think the documentation is lacking in clarity and there's an inconsistency with how
initialworks in a regularFormSet.With a
FormSet,extraforms are those beyond the ones created by the data ininitial, as documented here.With a
ModelFormSet, the data in the non-extra forms is determined by the existing model instances. It's sometimes useful to be able to pre-populate some of the extra forms with some initial data, and that's what theinitialparameter is used for. Ifinitialpre-populated the non-extra forms, how would the conflict with existing model instance data be resolved?If this were being designed from scratch, you could perhaps make a case that a
ModelFormSetshould consist of first the forms representing existing instances, then forms representing the giveninitialdata, then emptyextraforms (i.e.initialwould add more forms, not prepopulate theextraforms). This would perhaps be more consistent withFormSet, but I'm not sure it's actually better for real usage.In any case, if it's an improvement at all, it's not enough of one to justify making a backwards-incompatible change. So I'm converting this into a documentation bug; the
ModelFormSetdocs should have an explanation of howinitialandextrainteract differently in aModelFormSetthan in aFormSet.