Django formset_factory vs modelformset_factory vs inlineformset_factory

Posted

技术标签:

【中文标题】Django formset_factory vs modelformset_factory vs inlineformset_factory【英文标题】: 【发布时间】:2019-04-01 18:34:38 【问题描述】:

在 Django 中表单可能很复杂。 Formsets 可以让你想要退出 Django。我就在那个时候。

有哪些不同的用例以及使用哪一个的注意事项?

我正在寻找关于何时使用每个工厂的更好指导,因为它们似乎取决于您何时知道什么类型的表单、字段,以及您是否正在创建、编辑或删除(单个表单完全或完全是父模型)。我已经阅读了许多演练,但很难看到更大的图景,尤其是当我试图从基于函数的视图转移到基于类的视图时。

以下是一些带有假设/限制的伪代码,可帮助您帮助我理解差异。提供伪代码可能会有所帮助,例如 Formset 使用哪种表单(ModelForm 或常规),或者表单中的 popped 应该是什么,因为这似乎是创建具有关系的表单的趋势。

假设你有一些模型:

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)

而你想创建一个新的Meal,你想同时发送一个Reservation

您会使用哪个工厂? 是否取决于表格是否都是ModelForms? (意味着你将如何处理分配MealReservation) 假设: 在这个阶段你知道它是哪个Meal,但你仍然需要同时/相同的视图制作Reservation。 您不知道要烹饪哪个Dishes,因为预订会告诉您。 MealPhotos 还不存在,因为这顿饭还没准备好。 您想在同一个表单/屏幕上创建餐点和预订

然后,您想根据Reservation 所说的内容添加一些菜肴:

您会使用哪个工厂? 是否取决于表格是否都是ModelForms? 假设: 在这个阶段你知道Meal是哪个Reservation 您将根据 Reservation 为餐点分配菜肴,并且您有足够的信息来执行此操作,并且可以轻松使用 ModelForm,但不是必需的

后来吃菜的人要拍几张照片,不知道要拍几张

您会使用哪个工厂? 是否取决于表格是否都是ModelForms? 假设: 我们将要求他们至少参加两次 我们可以访问MealReservationDishes 可以选择将照片分配给Dish

【问题讨论】:

我对表格也有同样的看法。似乎它们是在考虑一些非常具体的用途的情况下构建的,如果你需要一些不同的东西,那么让所有部分很好地协同工作就变成了地狱。也在这里等待答案 【参考方案1】:

这3个formset工厂的区别基本是:

formset_factory 让您可以一起渲染一堆表单,但这些表单必须与特定的数据库模型相关(这不是您所需要的,因为您拥有适用于所有事物的模型) modelformset_factory 允许您一起创建/编辑一堆 Django 模型对象,例如,如果您正在管理“菜单”,您可以使用 modelformset_factory(Dish, fields=('name')) inlineformset_factory 让您可以管理一堆 Django 模型对象,这些对象都与另一个模型的单个实例相关。例如,如果您想管理在特定用餐时拍摄的所有 MealPhotos,这就是您可以使用的

回答您的具体场景:

如果您想要一个页面同时创建一个餐点和一个预订,而不分配任何菜肴,您不需要任何表单集。您可以只使用 ModelForm 进行用餐,使用 ModelForm 进行预订。

稍后,如果您想将多个菜肴附加到餐点,您可以使用inlineformset_factory(Meal, Dish) 来编辑属于单个餐点的多个菜肴

由于我们使用的是inlineformset_factory,我们必须在呈现表单的视图中创建 Meal 实例。像这样的:

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

对于上传餐点照片的人,您可以使用:

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

这告诉 Django 所有提交的照片都链接到那一餐,但允许将每张照片分配给不同的菜(通过表单中的下拉菜单)。

注意:在第一个场景中,我没有测试过表单集工厂是否支持使用 ManyToManyField 作为 Meal.dishes。如果不是,那么您可以简单地使用ModelFormset(Dish),然后在创建它们之后,将它们链接到处理表单提交的 Django 视图中的 Meal。

【讨论】:

这是我见过的三个表单集工厂的最清晰的总结。谢谢。但是您能否为 formset_factory 添加一个用例。你为什么要使用它以及它提供了什么并不很明显。 @BerndWechner 是否使用它是用户的选择,它存在的原因是在它提供的抽象之上构建另外两个(modelformset_factory 和 inlineformset_factory)。我见过经验不足的 django 开发人员,他们无法理解后者,使用基本的 formset_factory 并使他们的生活变得超级复杂。 当然,这显然是用户的选择。但要成为明智的选择,formset_factory 的用例将非常有用。

以上是关于Django formset_factory vs modelformset_factory vs inlineformset_factory的主要内容,如果未能解决你的问题,请参考以下文章

formset_factory 具有不同初始数据的表单

Django:如何在表单集构建后添加额外的表单?

重复的jquery ui问题

Django 1.7 vs Django1.6 vs Django 1.5 [关闭]

django.test.TestCase vs unittest vs django.utils.unittest.TestCase 之间的区别

Django - 保存前 VS 保存后 VS 查看保存