简体   繁体   中英

Django form validation with inline formsets

I have a main form and three inline forsets all on one HTML page for the purpose of creating Estimates for customers. The "main" form's primary key is used as the foreign key for all three inline formsets. I can create new estimates, save them, change the data, etc. no problem. However, it only works if all the required data is present and is "valid".

How do I go about having the HTML page be redisplayed with all the data entered but with errors shown in their proper spots?

To explain my situation further, the normal method for a single, simple form is something like this (this is off the top of my head so hopefully I don't have code errors):

if request.method=='POST':
    myform = Model_Form(request.POST)
    if myform.is_valid():
        myform.save()
        ...
        return HttpResponseredirect(...)
else:
    myform = new form from model etc...
return render_to_respose(template.html, {'myform':myform}, context_instance=RequestContext(request))

Now, with the above, if there are validation errors, the form is re-presented with the data the user already submitted with some errors beside the appropriate fields.

With inline formsets, we do something like this (assuming myForm has the PK and myInline uses that PK via a foreign key):

if request.method=='POST':
    myform = Model_Form(request.POST)
    if myform.is_valid():
        tmp = myform.save(commit=False)
        myInline = inlineFormset(request.POST, instance=tmp)
        if myInline.is_valid():
            myInline.save()
            myform.save()
            return HttpResponseRedirect(...)
else:
    myform = new form from model etc...
    myInline = new inline formset from model etc...
return render_to_respose(template.html, {'myform':myform, 'myInline':myInline}, context_instance=RequestContext(request))

So with the above code, if I have a validation error within myForm , we drop out of the if statement and redisplay the form to show errors. However, the inline form has not yet been created (the myInline = inlineFormset(request.POST, instance=tmp) line) because that step occurs after checking the myForm for validity and we get the error myInline Referenced before assignment or whatever.

To combat this, I tried moving the lines:

        tmp = myform.save(commit=False)
        myInline = inlineFormset(request.POST, instance=tmp)

prior to checking if myForm is valid so that I could capture the POST data for the inline form. But I can't do that because I haven't check if myForm is valid.

Chicken and the egg. Ugh!

So, how do I do validation and show entry errors for the forms while redisplaying the user entered content for the inline formsets?

Sorry for the long post but I don't know how to shorten the question.


EDIT:

Ok I figured out how to show the validation errors for the myForm main form and redisplay all the myForm fields as well as the myInline formset fields. It goes like this:

if request.method=='POST':
    myform = Model_Form(request.POST)
    if myform.is_valid():
        tmp = myform.save(commit=False)
        myInline = inlineFormset(request.POST, instance=tmp)
        if myInline.is_valid():
            myInline.save()
            myform.save()
            return HttpResponseRedirect(...)
    myInline = inlineFormset(request.POST)
else:
    myform = new form from model etc...
    myInline = new inline formset from model etc...
return render_to_respose(template.html, {'myform':myform, 'myInline':myInline}, context_instance=RequestContext(request))

I simply sneak in a new myInline assignment before stepping out of the main if statement.

Hopefully this helps someone else with this same problem.

Cheers!

Ok I figured out how to show the validation errors for the myForm main form and redisplay all the myForm fields as well as the myInline formset fields. It goes like this:

if request.method=='POST':
    myform = Model_Form(request.POST)
    if myform.is_valid():
        tmp = myform.save(commit=False)
        myInline = inlineFormset(request.POST, instance=tmp)
        if myInline.is_valid():
            myInline.save()
            myform.save()
            return HttpResponseRedirect(...)
    myInline = inlineFormset(request.POST)
else:
    myform = new form from model etc...
    myInline = new inline formset from model etc...
return render_to_respose(template.html, {'myform':myform, 'myInline':myInline}, context_instance=RequestContext(request))

I simply sneak in a new myInline assignment before stepping out of the main if statement.

Hopefully this helps someone else with this same problem.

Cheers!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM