views:

855

answers:

2

In my Django application application I have a formset that is created from a simple (not-model) form, with the extra=1 (to allow javasript to add more forms later on).

class SomeForm(forms.Form):
    #some fields with required=False
    length = forms.IntegerField(required=False)

    # An example of one of the fields with choices i have
    A = 0
    B = 1
    C = 2
    D = 3

    choices = ((A, 'Aah'), (B, 'Baa'), (C, 'Caa'), (D, 'Daa'))

    # This is a required choice field
    pickme = forms.ChoiceField(choices=choices)


SomeFormset = formset_factory(SomeForm, can_delete=True, extra=1)

Now, when I create and try to validate it in my view on the POST request:

my_formset = SomeFormset(request.POST, request.FILES)

if(my_formset.is_valid()):
    # FAIL

it always fails the above check, if the extra rendered form is submitted empty.

If I check for form.changed_data on the last empty extra form, I get the fields that have choices on them (like the pickme above). In other words, the formset is not smart enough to figure out that the empty submitted form should be ignored, when some choice fields are required.

+3  A: 

This is not the usual behavior of formsets. Formsets pass empty_permitted=True to all "extra" forms, and a form with empty_permitted that hasn't been modified should always pass validation. Note that this works just fine in the Django admin (if you use inlines).

You must be doing something else in your code that is breaking this behavior somewhere. Post the full code of the relevant form?

Carl Meyer
Thanks I'll look into it and get back to you
drozzy
IT turns out this is due to the choices field since forms.changed_data contains all my choices field that have no "empty" entry. I update the question to reflect that. I still don't have a good solution though.
drozzy
I figured it out! Thanks!
drozzy
+4  A: 

Thanks Carl, you led me to discover the root of my problem.

When creating a form with a choice field, which is required, we must set an initial value, otherwise the form will consider that field changed.

So for a form like this:

class SomeForm(forms.Form):

    A = 0
    B = 1
    C = 2
    D = 3

   choices = ((A, 'Aah'), (B, 'Baa'), (C, 'Caa'), (D, 'Daa'))

    # This is a required choice field
    pickme = forms.ChoiceField(choices=choices)

we do this:

pickme = forms.ChoiceField(choices=choices, initial=A)

Then when a formset checks the extra form it will see that pickme had an initial value of A, and it is A now as well, and will consider it unchanged.

drozzy
I'm having what seems to be the same bug, but providing an initial didn't actually solve the problem. Are you sure that was what actually fixed your problem?
Nope, but that's what fixed it.
drozzy
This answer solved a problem I was having. Thanks!
fholo
and what if I don't want to provide initial value of a field?
Lukasz Dziedzia
Then I can't help you my friend. This was a year ago - and I didn't use forms for a while. Let me know if you manage to solve it.
drozzy