Using Multiple Django Forms On One Page

July 18th, 2013

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.” 

July 2013

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