djangodjango-formsformsetinline-formset

Django formset_factory vs modelformset_factory vs inlineformset_factory


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:

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

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


Solution

  • The difference between the 3 formset factories is basically:

    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.