Creating formsets through AJAX

195 views
Skip to first unread message

Luper Rouch

unread,
Nov 19, 2008, 10:43:34 PM11/19/08
to Django users
Hi,

I am running into an annoying problem when trying to create formsets
dynamically.

I have a script that sends JSON data to a view to render it as a
formset. The response is then inserted in the page:

Script:
data = JSON.stringify([1, 2, 3]);
$("#container").load("render-form/", {data: data});

View:
def render_form(request):
data = simplejson.loads(request.POST["data"])
objs = [SomeModel(i) for i in data]
FormSet = modelformset_factory(SomeModel, extra=0)
forms = FormSet(queryset=objs)
return render_to_response("form_template.html", {"forms": forms})

It works but I get incorrect ManagementForm data in the output:

<input id="id_somemodel-TOTAL_FORMS" type="hidden" value="3"
name="attendee-TOTAL_FORMS"/>
<input id="id_somemodel-INITIAL_FORMS" type="hidden" value="3"
name="attendee-TOTAL_FORMS"/>

For django to save the formset correctly when it is submitted, I have to
manually set INITIAL_FORMS to 0 in javascript (because the objects are
not really in the database).

I tried to create the formset using extra=3 and passing the data via the
'initial' argument, but this gives an IndexError (django is trying to
set the forms 'instance' attribute from the queryset, but it is empty).

Is there a less hackish way to do this ?

Brian Rosner

unread,
Nov 19, 2008, 10:59:29 PM11/19/08
to django...@googlegroups.com
On Wed, Nov 19, 2008 at 8:43 PM, Luper Rouch <luper...@gmail.com> wrote:
> For django to save the formset correctly when it is submitted, I have to
> manually set INITIAL_FORMS to 0 in javascript (because the objects are
> not really in the database).

It looks like you are trying to shove a square object through a round
hole. Why are you using a model formset when there is "real" queryset?
Model formsets are simply a thin layer over formsets. It sounds like
you need to those to cleanly write your code and not resort to hacking
a model formset to work without a real queryset.

--
Brian Rosner
http://oebfare.com

Brian Rosner

unread,
Nov 19, 2008, 11:01:49 PM11/19/08
to django...@googlegroups.com

Ugh. That didn't read as well as I hoped :)

I meant to ask, why are you using model formsets when there is no
"real" queryset? You should just use formsets.

luper...@gmail.com

unread,
Nov 19, 2008, 11:14:21 PM11/19/08
to Django users
On 20 nov, 05:01, "Brian Rosner" <bros...@gmail.com> wrote:
> On Wed, Nov 19, 2008 at 8:59 PM, Brian Rosner <bros...@gmail.com> wrote:
> > On Wed, Nov 19, 2008 at 8:43 PM, Luper Rouch <luper.ro...@gmail.com> wrote:
> >> For django to save the formset correctly when it is submitted, I have to
> >> manually set INITIAL_FORMS to 0 in javascript (because the objects are
> >> not really in the database).
>
> > It looks like you are trying to shove a square object through a round
> > hole. Why are you using a model formset when there is "real" queryset?
> > Model formsets are simply a thin layer over formsets. It sounds like
> > you need to those to cleanly write your code and not resort to hacking
> > a model formset to work without a real queryset.
>
> Ugh. That didn't read as well as I hoped :)
>
> I meant to ask, why are you using model formsets when there is no
> "real" queryset? You should just use formsets.
>

django/forms/models.py is 747 lines long, I would not call that a thin
layer :)

I use it because I want to write forms that save models, and avoid
duplicating my model structure in the form class. Is'nt it what
modelforms are meant for ?

Brian Rosner

unread,
Nov 19, 2008, 11:33:56 PM11/19/08
to django...@googlegroups.com
On Wed, Nov 19, 2008 at 9:14 PM, luper...@gmail.com
<luper...@gmail.com> wrote:
>
> On 20 nov, 05:01, "Brian Rosner" <bros...@gmail.com> wrote:
>> On Wed, Nov 19, 2008 at 8:59 PM, Brian Rosner <bros...@gmail.com> wrote:
>> > On Wed, Nov 19, 2008 at 8:43 PM, Luper Rouch <luper.ro...@gmail.com> wrote:
>> >> For django to save the formset correctly when it is submitted, I have to
>> >> manually set INITIAL_FORMS to 0 in javascript (because the objects are
>> >> not really in the database).
>>
>> > It looks like you are trying to shove a square object through a round
>> > hole. Why are you using a model formset when there is "real" queryset?
>> > Model formsets are simply a thin layer over formsets. It sounds like
>> > you need to those to cleanly write your code and not resort to hacking
>> > a model formset to work without a real queryset.
>>
>> Ugh. That didn't read as well as I hoped :)
>>
>> I meant to ask, why are you using model formsets when there is no
>> "real" queryset? You should just use formsets.
>>
>
> django/forms/models.py is 747 lines long, I would not call that a thin
> layer :)

That file is not just model formset code. In terms of what a model
formset does, it is thin. It doesn't not change any behavior of a
regular formset. Just provides the additional layer to hook up with
models. I still consider that thin ;)

>
> I use it because I want to write forms that save models, and avoid
> duplicating my model structure in the form class. Is'nt it what
> modelforms are meant for ?

Then why are you not able to pass in a queryset? What data are you
sending to the server to generate the formset? From the little
explained code are they just primary keys?

luper...@gmail.com

unread,
Nov 19, 2008, 11:53:26 PM11/19/08
to Django users


On 20 nov, 05:33, "Brian Rosner" <bros...@gmail.com> wrote:
> On Wed, Nov 19, 2008 at 9:14 PM, luper.ro...@gmail.com
[1, 2, 3] is just some example data, not primary keys (actually I'm
passing dictionaries, but I tried to keep the example code short). It
is used to populate the formset, which is then rendered, inserted in
the page via an AJAX call, and eventually submitted to another view to
save it to the database.

I use a fake queryset because it's the only way that I found to
populate the formset (using a real queryset would lead to the same
problem anyway), hence I wonder if there is a cleaner way to do what I
want without reinventing modelforms, or using separate form classes
for saving and creating my dynamic formsets.

Brian Rosner

unread,
Nov 20, 2008, 12:01:03 AM11/20/08
to django...@googlegroups.com
On Wed, Nov 19, 2008 at 9:53 PM, luper...@gmail.com
<luper...@gmail.com> wrote:
>
> I use a fake queryset because it's the only way that I found to
> populate the formset (using a real queryset would lead to the same
> problem anyway), hence I wonder if there is a cleaner way to do what I
> want without reinventing modelforms, or using separate form classes
> for saving and creating my dynamic formsets.

I think from what I gather you are looking to create an "add"-only
model formset? If so take a look at
http://code.djangoproject.com/ticket/9538. I have written some
information on that ticket that may be of use to you.

luper...@gmail.com

unread,
Nov 20, 2008, 12:23:33 AM11/20/08
to Django users


On 20 nov, 06:01, "Brian Rosner" <bros...@gmail.com> wrote:
> On Wed, Nov 19, 2008 at 9:53 PM, luper.ro...@gmail.com
>
> <luper.ro...@gmail.com> wrote:
>
> > I use a fake queryset because it's the only way that I found to
> > populate the formset (using a real queryset would lead to the same
> > problem anyway), hence I wonder if there is a cleaner way to do what I
> > want without reinventing modelforms, or using separate form classes
> > for saving and creating my dynamic formsets.
>
> I think from what I gather you are looking to create an "add"-only
> model formset? If so take a look athttp://code.djangoproject.com/ticket/9538. I have written some
> information on that ticket that may be of use to you.
>

Yes I tried the approach you're talking about in the ticket:

FormSet = modelformset_factory(SomeModel, extra=3)

This creates 3 blank forms with INITIAL_FORMS=0, which is fine. But
then how can I populate this formset with some initial data instead of
the model's default values ? As I said:

forms = FormSet(initial=[{"field": 1}, {"field": 2}, {"field": 3}])

Or even:

forms = FormSet(queryset=SomeModel.objects.none(), initial=[{"field":
1}, {"field": 2}, {"field": 3}])

Does not work.

Brian Rosner

unread,
Nov 20, 2008, 12:54:46 AM11/20/08
to django...@googlegroups.com
On Wed, Nov 19, 2008 at 10:23 PM, luper...@gmail.com
<luper...@gmail.com> wrote:
>
>
>
> On 20 nov, 06:01, "Brian Rosner" <bros...@gmail.com> wrote:
>> On Wed, Nov 19, 2008 at 9:53 PM, luper.ro...@gmail.com
>>
>> <luper.ro...@gmail.com> wrote:
>>
>> > I use a fake queryset because it's the only way that I found to
>> > populate the formset (using a real queryset would lead to the same
>> > problem anyway), hence I wonder if there is a cleaner way to do what I
>> > want without reinventing modelforms, or using separate form classes
>> > for saving and creating my dynamic formsets.
>>
>> I think from what I gather you are looking to create an "add"-only
>> model formset? If so take a look athttp://code.djangoproject.com/ticket/9538. I have written some
>> information on that ticket that may be of use to you.
>>
>
> Yes I tried the approach you're talking about in the ticket:
>
> FormSet = modelformset_factory(SomeModel, extra=3)
>
> This creates 3 blank forms with INITIAL_FORMS=0, which is fine. But
> then how can I populate this formset with some initial data instead of
> the model's default values ?

Can you file a ticket about this? The fundamental issue here is that
formsets use initial data to populate the forms, but model formsets
make no distinction between initial data being passed in and initial
data it makes via the queryset. It sounds worth fixing.

luper...@gmail.com

unread,
Nov 20, 2008, 8:31:59 AM11/20/08
to Django users
On 20 nov, 06:54, "Brian Rosner" <bros...@gmail.com> wrote:
> On Wed, Nov 19, 2008 at 10:23 PM, luper.ro...@gmail.com
I think I misunderstood your first post, sorry. I tried to use
formset_factory with my ModelForm based form :

FormSet = formset_factory(SomeModelForm, extra=0)
forms = FormSet(initial=[{"field": 1}, {"field": 2}, {"field": 3}])

It works (I thought you _had_ to use modelformset_factory to create
ModelForm formsets). But then again, I get INITIAL_FORMS=3 in the
output. If I set extra to 3, I still get INITIAL_FORMS=3, and 3
additional blank forms, there seems to be no way to populate the extra
forms with initial data.

So I think a new keyword argument is needed for formset_factory to
solve this particular issue, perhaps extra_initial ?

luper...@gmail.com

unread,
Nov 20, 2008, 10:15:39 AM11/20/08
to Django users
On 20 nov, 14:31, "luper.ro...@gmail.com" <luper.ro...@gmail.com>
Looking closer at the details, the 'id' field is missing when using
formset_factory, which prevents django from saving the formset (I
still use a modelformset_factory based formset on the form's target
view to save the models). Using modelformset_factory is what gives the
closest result to what I want, but something like extra_initial would
make the whole thing way less hackish.

I will try to write a patch and file a ticket about it.
Reply all
Reply to author
Forward
0 new messages