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.
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!