Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django formset_factory vs modelformset_factory vs inlineformset_factory

Tags:

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
like image 229
chris Frisina Avatar asked Oct 28 '18 19:10

chris Frisina


People also ask

What is Modelformset_factory?

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.

What is modelformset_ factory in Django?

In Django, ModelFormsets is an advanced way to handle multiple forms created with a model. ModelFormSets uses the model to create model instances. Just as standard Django forms can be grouped together as a set in a Django FormSet , Django model forms can be grouped into a ModelFormSet .

What is Formset factory in Django?

Django model formsets provide a way to edit or create multiple model instances within a single form. Model Formsets are created by a factory method. The default factory method is modelformset_factory(). It wraps formset factory to model forms. We can also create inlineformset_factory() to edit related objects.

What is inline formset in Django?

Django formset allows you to edit a collection of the same forms on the same page. It basically allows you to bulk edit a collection of objects at the same time.


1 Answers

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.

like image 184
Lushen Wu Avatar answered Sep 21 '22 14:09

Lushen Wu