Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do a multi-step form in Django?

Tags:

django

I would like to create a mutli-step form in Django that only submits the data for processing at the end of all the steps. Each step needs to be able to access and display data that we entered in previous step(s).

Is there a way to do this with Django? Django's Form-Wizard can't handle this basic functionality.

like image 980
Saqib Ali Avatar asked Feb 15 '13 19:02

Saqib Ali


People also ask

What is multistep form?

A multi-step form is exactly what it sounds like — a long-form broken down into multiple pieces/steps to make an otherwise long form less intimidating for visitors to complete. The additional fields only appear after a visitor has filled in their baseline information, like name and email address.


2 Answers

Of course there's a way to do this in Django.

One way is to hold your values in session until you submit them at the end. You can populate your forms using values held in session if you return to previous step.

With some searching, you may find an app that someone has already written that will do what you want, but doing what you need isn't hard to do with Django, or any other framework.

Example, ignoring import statements:

#models/forms  class Person(models.Model):     fn = models.CharField(max_length=40)  class Pet(models.Model):     owner = models.ForeignKey(Person)     name = models.CharField(max_length=40)  class PersonForm(forms.ModelForm):     class Meta:         model = Person  class PetForm(forms.ModelForm):     class Meta:         model = Pet         exclude = ('owner',)  #views def step1(request):     initial={'fn': request.session.get('fn', None)}     form = PersonForm(request.POST or None, initial=initial)     if request.method == 'POST':         if form.is_valid():             request.session['fn'] = form.cleaned_data['fn']             return HttpResponseRedirect(reverse('step2'))     return render(request, 'step1.html', {'form': form})  def step2(request):     form = PetForm(request.POST or None)     if request.method == 'POST':         if form.is_valid():             pet = form.save(commit=False)             person = Person.objects.create(fn=request.session['fn'])             pet.owner = person             pet.save()             return HttpResponseRedirect(reverse('finished'))     return render(request, 'step2.html', {'form': form}) 

We'll assume that step2.html has a link to go back to step1.html.

You'll notice in the step1 view I'm pulling the value for fn from session that was set when the form was saved. You would need to persist the values from all previous steps into the session. At the end of the steps, grab the values, create your objects and redirect to a finished view, whatever that might be.

None of this code has been tested, but it should get you going.

like image 125
Brandon Avatar answered Sep 20 '22 00:09

Brandon


You can easily do this with the form wizard of django-formtools. A simple example would be something like the following.

forms.py

from django import forms  class ContactForm1(forms.Form):     subject = forms.CharField(max_length=100)     sender = forms.EmailField()  class ContactForm2(forms.Form):     message = forms.CharField(widget=forms.Textarea) 

views.py

from django.shortcuts import redirect from formtools.wizard.views import SessionWizardView  class ContactWizard(SessionWizardView):     def done(self, form_list, **kwargs):         do_something_with_the_form_data(form_list)         return redirect('/page-to-redirect-to-when-done/') 

urls.py

from django.conf.urls import url  from forms import ContactForm1, ContactForm2 from views import ContactWizard  urlpatterns = [     url(r'^contact/$', ContactWizard.as_view([ContactForm1, ContactForm2])), ] 
like image 31
Jonathan Potter Avatar answered Sep 21 '22 00:09

Jonathan Potter