Tuesday, May 5, 2015

Re: How to Process Multi Step Forms in Django?

I've finally figured it out after weeks of troubleshooting and here's how I do it.

In the original post, my views takes in the request from form1 and renders it to form2.  I would get the dreadful "Management Form Data is Missing" error no matter what I did and it led to asking a bunch of questions on here.  I decided to isolate the 2 forms to see if that rendered.  It took a few tries before getting both forms and templates to work separately.  What I noticed was form1.html's action was equal to "none" which was what I wanted.  It would render and posted the form with the errors to itself without redirecting to another page.  I then discovered that the address was still hooked to form1 instead of form2 after it had rendered.  In another word when form1 rendered the data to form2, the address was still on userinfo/form1.html when it should have been userinfo/form2.html in order for action to call the correct form in views.  The magic that I used to fix the issue was HttpResponseRedirect.  I saved the data retrieved from form 1 in a session and recovered it from beginning of form 2.  I used session to render data from form 2 instead of rendering directly from form 1.

Changes to form1 in views.py
  • Save the data in a session for access in different part of views
  • Re-direct to form2 instead of render data from form1
def form1 (request):
...
if formset.is_valid ():
            location = request.POST ['site']
            data
= formset.cleaned_data

            request
.session ['names'] = data

           
return HttpResponseRedirect ('form2')
...

Changes to form2 in views.py
  • Retrieve data from session
  • Do something with data from form2.   For my case, I merged both dictionary into one.

def form2 (request):

data = request.session ['names']
...
if checkbox_formset.is_valid ():
           
for i, form in enumerate (checkbox_formset.cleaned_data):
                data
[i].update (form)  # This will give me a list of name dictionary with the checkbox appended
 
  context
= {'data': data}
            return render (request, 'userinfo/success.html', context)
else:
        checkbox_formset
= CheckBoxFormSet (prefix = 'checkbox')

     context = {'checkbox_formset': checkbox_formset, 'data': data, 'location': location}
     
return render (request, 'userinfo/form2.html', context)


form2.html

<!DOCTYPE html>
<html>
<head lang="en">
   
<meta charset="UTF-8">
    {% load staticfiles %}
   
<link rel="stylesheet" type="text/css" href="{% static 'userinfo/style.css' %}" >
   
<title>Confirmation</title>
</head>
<body>
   
<h2>Submitted Entries:</h2>
   
<form action="form2" method="POST">{% csrf_token %}
   
<table>
     
<tr>
       
<th>Firstname</th>
       
<th>Lastname</th>
       
<th class="center">Location</th>
       
<th class="center">Overwrite</th>
       
<th class="center">Index</th>
     
</tr>
      {% for info in data %}
         
<tr>
           
<td>{{ info.first_name }}</td>
           
<td>{{ info.last_name }}</td>
           
<td class="center">{{ location }}</td>
            {{ checkbox_formset.management_form }}
           
<td class="center"><label for="id_checkbox-{{ forloop.counter0 }}-overwrite"></label>
               
<input id="id_checkbox-{{ forloop.counter0 }}-overwrite" name="checkbox-{{ forloop.counter0 }}-overwrite" type="checkbox"/></td>
           
<td class="center">{{ forloop.counter0 }}</td>
         
</tr>
      {% endfor %}
   
</table>
   
<p><input type="submit" value="Confirm">
   
<a href="{% url "addname" %}">
       
<button type="button">Cancel</button>
   
</a></p>
   
</form>
</body>
</html>

All there's left to do is create a template for success.html

<!DOCTYPE html>
<html>
<head lang="en">
   
<meta charset="UTF-8">
   
<title>Success</title>
</head>
<body>
   
<h2>Submitted Entries:</h2>
   
<ul>
        {% for info in data %}
           
<li>{{ info.first_name }} {{ info.last_name }} {{ info.overwrite }}</li>
        {% endfor %}
   
</ul>
   
<p><a href="{% url "addname" %}">Add more names</a></p>
</body>
</html>

Hope this will help some stragglers.  Nevertheless, thanks to Bernardo for helping me all along.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/df776fc2-c413-47ee-8703-11f530efffca%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment