Django nested inline formsets example
This Django project is purely to demonstrate an example of how to create a form that contains inline formsets that each contains its own inline formset.
I'm indebted to this blogpost by Ravi Kumar Gadila for helping me figure this out.
We have a model describing Publishers. Each Publisher can have a number of Books. Each Book can have a number of BookImages (e.g. its cover, back cover, illustrations, etc):
Publisher #1 |-Book | |-BookImage | |-BookImage | |-Book |-BookImage Publisher #2 |-Book | |-Book
See these in
Using an inline formset we could display a single form that would let the user edit all of the Books belonging to a single Publisher.
Using another inline formset we could display another form that would let the user edit all of the BookImages belonging to a single Book.
It becomes trickier if we want to combine these two forms into one: displaying all of the Books for a Publisher, and for each Book, all of its BookImages.
You can see in
forms.py how we construct an inline formset,
BookImageFormset for editing the
BookImages belonging to a single
And then we create a custom
BaseBooksWithImagesFormset that has a custom
nested property. This contains our
BookImageFormset. We add custom methods for
save() to ensure the data in these nested formsets are validated and saved.
Finally we create our
PublisherBooksWithImagesFormset which is for editing all the
Books belonging to a
Publisher... and we pass it this argument:
formset=BaseBooksWithImagesFormset so it knows how to handle each of the
views.py for how we use this in a class-based view to create the page. This expects the
id of a
Publisher. And see the
books/publisher_books_update.html template for how the outer form, and its
Book formsets, and their nested
BookImage formsets, are rendered.
Here's an image showing how that page looks:
If you want to get this project running to see how it works...
Download or clone the repository.
Install Django and Pillow (required for the
ImageField). For example, using pip with the
pip install -r requirements.txt
Or using pipenv with the
Run the migrations:
Create a superuser if you want to use the Django Admin:
Run the development server:
View the site at http://127.0.0.1:8000/ and add at least one Publisher.
You can then click the link to add some Books to your Publisher. You'll then be on a page like http://127.0.0.1:8000/publishers/1/books/edit/ which is the form with its inline formsets.