title: Creating a multi-step form using a ModelForm in Django
body: <p>I am attempting to create a multi-step ModelForm using a library called <a href="https://django-formtools.readthedocs.io/en/latest/wizard.html#how-to-work-with-modelform-and-modelformset" rel="nofollow noreferrer">FormWizard</a>. However, I am having difficulty getting the results I want.</p>
  
  <blockquote>
    <p><strong>Work Flow</strong></p>
  </blockquote>
  
  <pre class="lang-none prettyprint-override"><code>User clicks on create patient link
  User opens patient form
  User inserts patient data
  User submits form
  if form is invalid:
      redisplay form with error 
  if form is valid:
      move to next form 
      enter symptom data
      submit form
  if form is invalid:
      redisplay form with error 
  if form is valid:
      move to next form 
      enter disease data
      submit form
  if form is invalid:
      redisplay form with error
  if form is valid:
      User is redirected to general form that has patient + symptom + disease information.
  </code></pre>
  
  <blockquote>
    <p><strong>View that will create the multi-step ModelForm</strong></p>
  </blockquote>
  
  <pre><code>class ConsultationCreate(SessionWizardView):
  
      instance = None
  
      def get_form_instance(self, step):
          if self.instance is None:
              self.instance = Patient
          return self.instance
  
      template_ = 'data/multi_form.html'
  
      def done(self, form_list, **kwargs):
          self.instance.save()
  
  
  def process_form_data(form_list):
  
      form_data = [form.cleaned_data for form in form_list]
  
      logr.debug(form_data[0]['NIS'])
      logr.debug(form_data[1]['identity'])
      logr.debug(form_data[2]['identity'])
  
      return form_data
  </code></pre>
  
  <blockquote>
    <p><strong>This is the error it produces</strong>:</p>
  </blockquote>
  
  <pre><code>ValidationError at /patient/create
  ['ManagementForm data is missing or has been tampered.']
  </code></pre>
  
  <h3>The code</h3>
  
  <blockquote>
    <p><strong>urls.py</strong></p>
  </blockquote>
  
  <pre><code>from django.conf.urls import url
  from data.views import IdentityList, IdentityCreate, IdentitySpecific, ConsultationCreate, MultiStep
  from data.forms import  SymptomForm, DiseaseForm, IdentityForm
  
  urlpatterns = [
          url(r'^patient/$', IdentityList.as_view(),  name = 'data_patient_list'),
  
          url(r'^patient/create$', ConsultationCreate.as_view([IdentityForm, SymptomForm, DiseaseForm]),  name = 'data_patient_create'),
  
  ]
  </code></pre>
  
  <blockquote>
    <p><strong>models.py</strong></p>
  </blockquote>
  
  <pre><code>    from django.db import models
      from django.utils import timezone
      from django.shortcuts import reverse
      import datetime
  </code></pre>
  
  <blockquote>
    <p>Creates Patient database</p>
  </blockquote>
  
  <pre><code>class Patient(models.Model):
  
      NIS =models.CharField(max_length = 200, primary_key = True)
      timestamp = models.DateTimeField(auto_now = True)
      first_name = models.CharField(max_length = 80, null = True)
      last_name = models.CharField(max_length = 80, null = True )
      contact = models.CharField(max_length = 15, null = True)
      location  = models.CharField(max_length = 100, blank = True)
      email_address = models.EmailField()
  
      CHOOSE = 'The patient is'
      MALE = 'M'
      FEMALE = 'F'
      personGender = ((CHOOSE,'The patient is'),(MALE, 'Male'),(FEMALE,'Female'),)
      gender = models.CharField(max_length=2,choices=personGender,default=CHOOSE)
  
      born = models.DateField(auto_now = False, auto_now_add = False, blank = True, null = True)
  </code></pre>
  
  <blockquote>
    <p>Creates Symptom database</p>
  </blockquote>
  
  <pre><code>class Symptom(models.Model):
  
      identity = models.CharField('Name of symptom', max_length = 80, default = '')
      description = models.TextField(max_length = 1000, default = '')
      patient = models.ManyToManyField(Patient,  through = 'Consultation')
  
      def __str__(self):
          return '%s' % ( self.identity )
  </code></pre>
  
  <blockquote>
    <p>Creates Disease database</p>
  </blockquote>
  
  <pre><code>class Disease(models.Model):
  
      identity = models.CharField('Name of disease', max_length = 80, default = '')
      description = models.TextField(max_length = 5000, default = '')
      symptom = models.ManyToManyField(Symptom)
  
      def __str__(self):
          return '%s' % ( self.identity )
  </code></pre>
  
  <blockquote>
    <p>Consultation model is the intermediate model</p>
  </blockquote>
  
  <pre><code>class Consultation(models.Model):
      patient_identity = models.ForeignKey(Patient)
      patient_condition = models.ForeignKey(Symptom)
      patient_disease = models.ForeignKey(Disease)
      patient_treatment = models.ForeignKey(Treatment)
      consultation_date_and_time = models.DateTimeField('visitation date and time', auto_now = False, auto_now_add = False, blank = True, null = True)
  
      # Use get_absolute_url to access single page model objects that possess a Canonical Uniform resource locator
      def get_absolute_url(self):
          return reverse('data_patient_detail', kwargs={'pk':self.pk})
  </code></pre>
  
  <blockquote>
    <p><strong>views.py</strong></p>
  </blockquote>
  
  <pre><code>from data.models import Treatment, Symptom, Disease, Consultation, Patient
  from django.shortcuts import get_object_or_404, render, redirect, render_to_response
  from django.views.generic import View
  from data.forms import IdentityForm
  from formtools.wizard.views import SessionWizardView
  </code></pre>
  
  <blockquote>
    <p>Class based view for patient list</p>
  </blockquote>
  
  <pre><code>class IdentityList(View):
      template_ = 'data/patient_list.html'
      def get(self, request):
          patient_list = Consultation.objects.all()
          return render(request, self.template_, {'patient_list':patient_list})
  </code></pre>
  
  <blockquote>
    <p>Class based view for patient detail</p>
  </blockquote>
  
  <pre><code>class IdentitySpecific(View):
      model = Consultation
      template_ = 'data/patient_detail.html'
      def get(self, request, pk):
          patient_consult = Consultation.objects.filter(pk=pk)
          return render(request, self.template_, {'patient_consult':patient_consult})
  </code></pre>
  
  <blockquote>
    <p>Class based view for multi-step modelform</p>
  </blockquote>
  
  <pre><code>class ConsultationCreate(SessionWizardView):
      instance = None
      def get_form_instance(self, step):
          if self.instance is None:
              self.instance = Patient
          return self.instance
  
      template_ = 'data/multi_form.html'
  
      def done(self, form_list, **kwargs):
          self.instance.save()
  </code></pre>
  
  <blockquote>
    <p>Function process_form_data using to process form data in
    ConsultationCreate view</p>
  </blockquote>
  
  <pre><code>def process_form_data(form_list):
      form_data = [form.cleaned_data for form in form_list]
      logr.debug(form_data[0]['NIS'])
      logr.debug(form_data[1]['identity'])
      logr.debug(form_data[2]['identity'])
      return form_data
  </code></pre>