Passing data to formsets.

How do I pass some initial data to a formset ? What I am trying to do is

  1. Render a formset
  2. After the form is submitted, get the cleaned data and save it to request.session["some_key"]
  3. if request.session["some_key"] is not None, I pass it to the instantiated formset class in the get method of a CBV.

This works fine for other normal forms I have but I face difficulty in formsets. For normal forms, I could just save the data in session and then pass that in GET method of the View to have the form repopulated.

You need to instantiate the formset with the initial parameter. Formsets | Django documentation | Django

Did you mean form here?

I did. The following is an example snippet.

from django.shortcuts import render
from django.views import View
from .forms import ExampleFormSet

class ExampleView(View):

    def get(self, request, *args, **kwargs):
        data = { 'form-TOTAL_FORMS': '3', 'form-INITIAL_FORMS': '0', }
        example_form = ExampleFormSet(data)
        context = { "example_form": example_form }
        if request.session.get("saved_data") is not None:
            print(request.session.get("saved_data"))
            example_form = ExampleFormSet(initial=request.session.get("saved_data"))
            context = { "example_form": example_form }
            return render(request, "base/main.html", context)
        return render(request, "base/main.html", context)

    def post(self, request, *args, **kwargs):
        data = { 'form-TOTAL_FORMS': '3', 'form-INITIAL_FORMS': '0', }
        example_form = ExampleFormSet(request.POST)
        if example_form.is_valid():
            request.session["saved_data"] = example_form.cleaned_data

        context = { "example_form": example_form }
        return render(request, "base/main.html", context)

forms.py

from django import forms
from django.forms import formset_factory, BaseFormSet

class ExampleForm(forms.Form):

    sample_field = forms.FloatField(
        widget = forms.TextInput(attrs = { "required": "required" })
    )

ExampleFormSet = formset_factory(ExampleForm, extra=3)

This however, causes 3 more fields to appear on every GET request to the ExampleView

  1. TOTAL_FORMS and INITIAL_FORMS are variables calculated by Django for validation purposes. You don’t have to pass them when instantiating a formset:
data = { 'form-TOTAL_FORMS': '3', 'form-INITIAL_FORMS': '0', }
example_form = ExampleFormSet(data)

  1. This however, causes 3 more fields to appear on every GET request to the ExampleView

This is the expected behaviour.

ExampleFormSet = formset_factory(ExampleForm, extra=3)

The extra arg indicates that everytime the formset is instantiated, it should include 3 empty forms.


  1. If you need to define a max n° of forms you could use max_forms
ExampleFormSet = formset_factory(ExampleForm, max_forms=3)

If I don’t pass these in, I always get the management form error.

How are you rendering the formset in the template?

From the docs:

The management form is available as an attribute of the formset itself. When rendering a formset in a template, you can include all the management data by rendering
{{ my_formset.management_form }} (substituting the name of your formset as appropriate).

Thanks for pointing this out. It worked !