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 pop
ped 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:
ModelForms
? (meaning how would you handle assignming the Meal
its Reservation
)Meal
it is, but you still have to make a Reservation
at the same time/same view.Dish
es you are going to cook, since the reservation will tell you.MealPhotos
won't exist yet since the meal isn't prepared yet. Then later, you want to add some dishes, based on what the Reservation
says:
ModelForms
?Meal
it is, and you have a Reservation
Reservation
, and you have enough information to do so, and can use a ModelForm easily, but not requiredLater, the person eating the dish wants to take some photos, and you don't know how many they will take
ModelForms
?Meal
, Reservation
, and Dishes
Dish
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.
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 .
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.
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.
The difference between the 3 formset factories is basically:
modelformset_factory(Dish, fields=('name'))
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With