Django Class-based Views with Multiple Forms

By default some of Django’s class-based views support just a single form per view. This, of course, does not always play nicely with what you’re trying to accomplish. I’ve yet to come across a concrete example of how to accomplish this so after a bit of experimentation and some time spent diving into Django’s code, I’ve created a decent workaround. Please let me know in the comments if there’s a better way to do this.

For this example I’ll use a generic UpdateView and two ModelForms. The same technique should work with most of the class-based views as well as regular forms.

I’ll also mention that this handles the validation and submission of either form, but not both forms at the same time. The user is only submitting a single form, so you only need to handle that one.

There’s nothing special about the models or the templates, so let’s look at the view:

The first thing the view does is set the template, success_url and the two forms. Next we define the get_context_data method which adds either form to the context if it is missing.

UPDATE: There was an issue with the get_context_data method in which the form would not be populated with values from the model if a form was submitted with invalid data (and self.form_invalid was called). The current fix is to manually pass the data to the form using the initial argument.

The get_object method overrides the default behavior and gets a model instance based on a session variable. This isn’t necessary if you’re using the standard method of providing a pk or slug in the URL.

The next change is very important – override the default form_invalid method. The default method returns a single form in the context:

Since we have two forms, with different names, we need to switch to using **kwargs instead.

Finally, we override the post method to determine which form was submitted based on the name of the submit button (you could alternatively use a hidden field), validate the form and call form_valid or form_invalid. These methods will save the form and redirect to the success_url, or return to the view and show any errors, respectively.

And for the sake of clarity, the forms in your templates simply need a named submit button:

5 thoughts on “Django Class-based Views with Multiple Forms”

  1. Hi from Argentina, Im new in python and django, Im working in my first proyect in django and I want to render multiple forms on a single template. Im working with class based generic views and class based views. Do you have a complete example to help me?

    Thanks a lot!!

  2. I’ve already used some of your insights from another post, and here again you are in my Google search!

    Just a thought to keep this in line with the djang-onic (or is it djangoic?) way of creating model views and how they handle being inherited later;

    You could add:

    def get_second_form_class():
    return self.second_form_class

    And change later instances of:




    That way if the view is inherited by another it still allows you to change the form class of the second form easily with the `second_form_class` variable, just like how Django handle updating form_class. Otherwise if you set `second_form_class` in a child view/class it will have no effect.

      1. On second thought, that doesn’t work how I thought it would – or rather, there wasn’t an inheritance issue.

        I swear I just ran into this though. I need to look back at what I did… and now I think I’m taking crazy pills.

        Your could still refactor to follow their conventions, but that seems somewhat unnecessary as your code should inherit fine as it is.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s