How to save multiple models with multiple modelForms in one django form-tools WizardView

639 Views Asked by At

Here's my scenario:

I have two models:

class Person(models.Model):
    # --- model fields ---

class Qualification(models.Model):
    owner = models.ForeignKey(Person, on_delete=models.CASCADE)
    # --- other fields --- 

And Model forms:

class PersonalForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = ['first_name', 'last_name', 'email', 'id_number', 'date_of_birth']

class IsQualifiedForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = ['is_qualified']

class QualificationForm(forms.ModelForm):
    class Meta:
        model = Qualification
        fields = ['level', 'course_name', 'attainment']

And finally my wizard view:

class Wizard(SessionWizardView):
    template_name = 'demo/wizard_test.html'
    form_list = [
        ("personal", PersonalForm),
        ("is_qualified", IsQualifiedForm),
        ("qualifications", QualificationForm),
    ]

    def get_form_instance(self, step):
        return self.instance_dict.get(step, None)

    def done(self, form_list, **kwargs):
        # What is the exact logic to be applied here to save the model forms concurrently?
        return redirect('home')

I'm trying to save the form but I run into errors:

When I try to call:

for form in form_list:
    form.save()

in the done() method, I get an error because the is_qualified is intercepted as null in the first step.

Plus, how do I get to set the owner field's value to the currently created person?

Any help would be appreciated.

1

There are 1 best solutions below

0
On BEST ANSWER

If is_qualified is not nullable in your Person model, validation will always fail. What you can do is save both PersonalForm and IsQualifiedForm in one go, since they refer to the same model anyways. To do this, set the values of one form in the other. For example:

def done(self, form_list, **kwargs):
    person = form_list[0].save(commit=False)
    person.is_qualified = form_list[1].cleaned_data['is_qualified']
    person.save()
    return redirect('home')

Some notes:

  1. You should probably use named steps instead of relying on form index
  2. If your case is as simple as the form you provided, you should just make the first two forms a single form