Dynamic Formsets in Django

Adding forms dynamically to a Django formset

Django Forms

Forms in HTML are a collection of input elements that allows us to perform dynamic actions on a website. Django models these forms as an object of Form class. A form is responsible for taking input from a user, validating and cleaning data and taking necessary action as required.

Formsets

A formset is a collection of Django Forms. Each formset has a management form which is used to manage the collection of forms contained in it.

Formset stores data like the total number of forms, the initial number of forms and the maximum number of forms in a management form. So whenever we want to add a form dynamically on the frontend, we need to change the total number of forms so that “Management form has been tampered error is not thrown”. All the forms in a formset are numbered sequentially, so we need to do a little processing of these numbers to keep the whole structure of a form consistent.

Let’s consider an example of a library wherein form is required to fill details of Book. The Book model looks like

Use case 1: Create formset for a normal form

Let’s create a view wherein a user can add and store multiple books at once. For this, we will need a form, whose formset can be made. We will first start with a normal form and see how we can make formsets using normal form. We are using Bootstrap to power our styling.

Dynamic Formsets

The form definition will look like this

Let’s create a formset for this form using formset_factory . The updated forms.py will look like this

Now, let’s use this form in a view and create an interface where a user can add or store multiple books

The template code to render and iterate over this formset will look like

This code will simply render the form. By default, a single element will be present, since we have passed extra as 1 when creating BookFormset . Note that here three class variable names are important. They are form-row , add-form-row and remove-form-row . For better clarity, they are explained below.

form-row : The row which you want to clone. It should have all the input element along with the Add more/Remove this button.

: The row which you want to clone. It should have all the input element along with the Add more/Remove this button. add-form-row : The button which is responsible for adding similar rows

: The button which is responsible for adding similar rows remove-form-row: The button which is responsible for the selected row.

You can tweak these names as per your convenience.

Now we need to add some javascript code, to give the functionality of adding form elements when + button is pressed and removing form elements when - button is present.

This code will look like

When this code is added in create_normal.html , the functionality becomes complete wherein a user can add and remove form elements on the fly.

Use case 2: Create formset for a model form

Lets us consider the same problem, where we want to add multiple books, but this time using a ModelForm , rather than using a simple form. Since we are using ModelForm , a ModelFormset will be created.

The code for the views will be slightly changed. Here rather than creating a Book model instance and then saving it, form will be used, since form is an instance of ModelForm .

The template code(part 3) and javascript code(part 4) remains the same.

Use case 3: Create Formset and Form both

Let’s consider a more complex case wherein we need to save form along with a formset. This can be easily understood by taking the example of Book and Author . Here we will create a modelform for Book and modelformset for Author .

Form with Formsets

The corresponding code for the views will look like

The template code to iterate and render both the form and formset will look like

Conclusion

This post walked in detail of how can the formsets be implemented. Much of the help for the above javascript code is taken from this stackoverflow answer.

The code for this can be found here

Updates