Is it possible to submit multiple forms at once using Django views?

Issue

What I want to accomplish is to be able to submit multiple forms contained on one page. What I have currenlty done is supplied a view that returns 8 forms. Is it possible, within the template, to have lets say a button that will submit all of the forms contained on the page in one POST request?

Here is some code from my view:

def get_all_forms(request):
    context = {}
    if request.method == 'POST':
        return
    else:
        for x in range(8):
            context[x] = Form()
    return render(request, 'app/all_forms.html', {'form': context})

Solution

Some issues with your code:

  1. It lacks input validation.

  2. You probably won’t be able to differentiate between the data submitted by the 8 instances of Form(), because all instances will have the same HTML name attribute for the <input .../> elements.

    One way to make the instances distinct is to use the prefix keyword argument. For example:

    def get_all_forms(request):
        NUM_FORMS = 8
        if request.method == 'POST':
            forms = [Form(request.POST, prefix=i) for i in range(NUM_FORMS)]
            if all((form.is_valid() for form in forms)):
                # Do something with the submitted data here ...
                return redirect('somewhere ......')
        else:
            forms = [Form(prefix=i) for i in range(NUM_FORMS)]
        return render(request, 'app/all_forms.html', {'forms': forms})
    

    But a much better solution is to use formsets (see below).

Solution

Formsets allow you to have multiple copies of the same form on one page, and process all of them in one POST request. Using a formset, Django is able to handle validation for all the forms. Example:

If your form is:

from django import forms

class MyForm(forms.Form):
    # ...

Create a formset that has 8 empty forms:

from django.forms import formset_factory

MyFormset = formset_factory(MyForm, extra=8)  # Create 8 forms.

Then you can use the formset in your view:

from django.shortcuts import redirect, render

def get_all_forms(request):
    if request.method == 'POST':
        formset = MyFormset(request.POST)
        if formset.is_valid():  # Validates all 8 forms.
            # ... (submitted data is in formset.cleaned_data)
            return redirect('somewhere ......')
    else:
        formset = MyFormset()
    return render(request, 'app/all_forms.html', {'formset': formset})

And you can display all forms in your template using just this:

<form action="" method="post">
    {% csrf_token %}
    <table>
        {{ formset }}
    </table>
    <input type="submit"/>
</form>

Further information from the documentation:

Answered By – Flux

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published