Django formset_factory vs modelformset_factory vs inlineformset_factory
Asked Answered
S

2

34

Forms can be complicated in Django. Formsets can make you want to quit Django. I'm at that point.

What are the different use cases and considerations of which one(s) to use?

I'm looking for some better guidance as to when to use each factory, as they seem to depend on when you know what type of form, fields, and whether or not you are creating, editing, or deleting (individual forms entirely or the parent model altogether). I have read many walkthroughs, but am struggling to see the larger picture, especially as I am attempting to move from function based views to Class Based Views.

Below are some pseudo code with assumptions/restrictions to help you help me understand the differences. It may help to provide psuedocode, such as what kind of Form (ModelForm or regular) goes with the Formset, or what should be popped from the form, given this seems to be a trend for creating forms with relations.

Assuming you have some models:

class Dish(models.Model):
    name = models.CharField(max_length=50)


class Meal(models.Model):
    name = models.CharField(max_length=50)
    dishes = models.ManyToManyField(Dish,
                                    # through='OPTIIONALMealDishIntermediaryClassTable',
                                    related_name="meal")

class Reservation(models.Model):
    date = models.DateTimeField()
    greeting = models.CharField(max_length=255)
    meal = models.OneToOneField(Meal, on_delete=models.CASCADE)


class MealPhotos(models.Model):
    photo = models.OneToOneField(Photo, on_delete=models.CASCADE, related_name='mealPhoto')
    meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
    # optional, so a photo can be attached to a dish if the picture is just of the dish
    dish = models.ForeignKey(Dish, blank=True, null=True, on_delete=models.CASCADE)

And you want to create a new Meal, you want to send a Reservation at the same time:

  • which factory would you use?
  • does it depend on if the forms are all ModelForms? (meaning how would you handle assignming the Meal its Reservation)
  • assuming:
    • at this stage you know which Meal it is, but you still have to make a Reservation at the same time/same view.
    • you don't know which Dishes you are going to cook, since the reservation will tell you.
    • MealPhotos won't exist yet since the meal isn't prepared yet.
    • You want to create the meal and the reservation on the same form/screen

Then later, you want to add some dishes, based on what the Reservation says:

  • which factory would you use?
  • does it depend on if the forms are all ModelForms?
  • assuming:
    • at this stage you know which Meal it is, and you have a Reservation
    • you are going to assign dishes to the meal based on the Reservation, and you have enough information to do so, and can use a ModelForm easily, but not required

Later, the person eating the dish wants to take some photos, and you don't know how many they will take

  • which factory would you use?
  • does it depend on if the forms are all ModelForms?
  • assuming:
    • we will require them to take at least two
    • we have access to the Meal, Reservation, and Dishes
    • a photo could optionally be assigned to a Dish
Solecism answered 28/10, 2018 at 19:9 Comment(1)
I'm at the same point as well with the forms. It seems like they were build with some pretty specific usage in mind and if you need something different it becomes hell to make all parts work well together. Waiting for an answer here as wellTowny
M
41

The difference between the 3 formset factories is basically:

  • formset_factory lets you render a bunch of forms together, but these forms are NOT necessarily related to a particular database models (this is not what you need, since you have models for everything)
  • modelformset_factory lets you create/edit a bunch of Django model objects together, for example, if you were managing the "menu" you could use a modelformset_factory(Dish, fields=('name'))
  • inlineformset_factory lets you manage a bunch of Django model objects that are all related to a single instance of another model. For example, if you wanted to manage all of the MealPhotos that were taken at a particular Meal, this is what you would use

To answer your specific scenarios:

If you wanted a page that created a single Meal and a single Reservation at the same time, without assigning any Dishes yet, you don't need any formsets. You could just use a ModelForm for Meal and a ModelForm for Reservation.

Later on, if you want to attach multiple Dishes to the Meal, you would use an inlineformset_factory(Meal, Dish) to edit multiple Dishes belonging to a single Meal

Since we are using an inlineformset_factory, we have to create the Meal instance in the view that renders the form. Something like this:

DishFormSet = inlineformset_factory(Meal, Dish)
bday_dinner = Meal.objects.create(name='30th Birthday dinner')
formset = DishFormSet(instance=bday_dinner)

For someone uploading photos of the Meal, you would use:

PhotosFormSet = inlineformset_factory(Meal, MealPhotos)
bday_dinner = Meal.objects.get(name='30th Birthday dinner')
formset = PhotosFormSet(instance=bday_dinner)

This tells Django that all the photos submitted are all linked to that one Meal, but allows the possibility of assigning each photo to a different Dish (via a dropdown in the form).

Note: In the first scenario, I haven't tested whether you the use of a ManyToManyField as Meal.dishes is supported by the formset factory. If it isn't, then you could simply use a ModelFormset(Dish) and after those are created, link them to the Meal in the Django view that process the form submission.

Mincing answered 10/11, 2019 at 0:24 Comment(4)
This is the most lucid summary of the three formset factories I've seen yet. Thanks. But could you perhaps add a use case for formset_factory. It's not really evident why you'd use that at all and what it offers.Rayfordrayle
@BerndWechner to use it or not, is the user's choice, and the reason for it's existence is to build the other two (modelformset_factory & inlineformset_factory) on top of the abstraction it provides. I've seen less experienced django developers who cannot make sense of the latter, use base formset_factory and make their lives super complicated.Thomasina
Sure, it is obviously the user's choice. But to be an informed choice, a use case for formset_factory would be of great utility.Rayfordrayle
@BerndWechner Almost two years later, but I’m encountering a use case for base formset_factory at the moment. I’m making a form that I send to Vendors to upload their invoices, and each invoice pertains to a Cost model. Vendors might have invoices for multiple Jobs (i.e. they might have multiple associated Costs) so I’m using a base formset to update the invoice status of each Cost when an invoice is sent received. Seems to be the only formset type that would make sense for this particular case.Rive
P
0

There's 4 types of formset

  1. modelform_factory: create a modelform for a given model and for a single instance of a model.
  2. inlineformset_factory: create a formset related models, aim for a parent-child relationship.
  3. modelformset_factory: create a model formset for a given model and for managing multiple instance of a model at once.
  4. formset_factory: create a formset not necessarily to tied to a model.
Pericline answered 6/7 at 4:49 Comment(1)
Where did you find it? If you found it in the existing answer your post is just "Thanks." which is off-topic and should be deleted. It otherwise risks being flagged and deleted. If you found it elsewhere please state the source and author in order to avoid the impression of plagiarism. Please take the tour and read How to Answer.Particle

© 2022 - 2024 — McMap. All rights reserved.