Using Multiple Django Forms On One Page

Django has some really great forms. Their Forms API is rich, reusable, and generally a pleasure to work with. Many things in web development start with accepting input from the user, so having this in your toolkit is a great productivity boost when developing. Django also has ModelForms which allow a very simple form to be created and validated based on a model’s fields. This enables rapid prototype development.

One catch I ran into early on is combining ForeignKey relations with various ModelForm instances. Django’s admin site has a whole separate pop-up window that will take care of this for you, but that’s a little invasive and frankly too old school 1 for our applications. My default previously was to use a ForeignKey that defaulted to None and then force a separate page that handled filling in the new model.

Forget all that dumbassery.

Django forms (yes, ModelForm instances too) allow you to prefix field names by instantiating them in a constructor. Without too much more talk, let’s dive into some code examples.

# Initalize our two forms here with separate prefixes
form = SchoolForm(prefix="sch")
sub_form = LocationForm(prefix="loc")

# Check to see if a POST has been submitted. Using GET to submit forms?
# Don't do it. Use POST.
if request.POST:
    # Load up our two forms again using the prefix keyword argument.
    form = SchoolForm(request.POST, prefix="sch")
    sub_form = LocationForm(request.POST, prefix="loc")

    # Ensure both forms are valid before continuing on
    if form.is_valid() and sub_form.is_valid():
        # Prepare the school model, but don't commit it to the database
        # just yet.
        school = form.save(commit=False)

        # Add the location ForeignKey by saving the secondary form we
        # setup
        school.location = sub_form.save()

        # Save the main object and continue on our merry way.
        school.save()
        return _goto_school(school)

# Continue request processing and handle rendering whatever template

In the template we can do something like this.

 <form method="POST">
     <h2>School Information:</h2>
     <!-- Make use of Django's automatic form templating -->
     {{ form.as_p }}

     <!-- Now add the sub-form to this form -->
     <h3>Location Information:</h3>
     {{ sub_form.as_p }}
     <p><button type="submit">Add School</button></p>
 </form>

  1. We’ve actually had clients complain that the admin site looks “like it was pulled straight from 1998.” ↩︎

written July 18th, 2013

July 2013

Can’t find what you’re looking for? Try hitting the home page or viewing all archives.