django forms:在单个表单中编辑多组相关对象
我正在尝试做一些应该很常见的事情:以单一形式添加/编辑一堆相关模型。例如:
Visitor Details:
Select destinations and activities:
Miami [] - swimming [], clubbing [], sunbathing[]
Cancun [] - swimming [], clubbing [], sunbathing[]
我的模型是访客、目的地和活动,访客通过中间模型 VisitorDestination 将 ManyToMany 字段放入 Destination,该模型具有要在目的地上完成的活动的详细信息(本身就是 Activity 中的 ManyToMany 字段)。
Visitor ---->(M2M though VisitorDestination) -------------> Destination
|
activities ---->(M2M)---> Activity
请注意,我不想输入新目的地/活动值,只需从数据库中可用的值中选择(但这是 M2M 字段的完全合法使用,对吧?)
对我来说,这看起来是一种极其常见的情况(与其他模型中的 FK 或 M2M 字段的附加细节的多对多关系),这看起来是最明智的建模,但如果我错了,请纠正我。
我花了几天时间搜索 Django 文档/SO/谷歌搜索,但一直无法弄清楚如何处理这个问题。我尝试了几种方法:
访客的自定义模型表单,我在其中添加了目的地和活动的多个选择字段。如果可以独立选择目的地和活动,那就没问题,但这里它们相关,即我想为每个目的地选择一项或多项活动
使用
inlineformset_factory
使用inlineformset_factory(Destination, Visitor)
生成目的地/活动表单集。这会破坏,因为访问者与目的地具有 M2M 关系,而不是 FK。使用
formset_factory
自定义普通表单集,例如DestinationActivityFormSet = formset_factory(DestinationActivityForm, extra=2)
。但是如何设计DestinationActivityForm
呢?我还没有对此进行足够的探索,但它看起来不太有希望:我不想输入目的地和活动列表,我想要一个复选框列表,其中标签设置为我想要的目的地/活动进行选择,但formset_factory
将返回具有相同标签的表单列表。
我是 django 的新手,所以也许解决方案是显而易见的,但我发现该领域的文档非常薄弱 - 如果有人有一些关于表单/表单集的使用示例的指示,那也会很有帮助,
谢谢!
I'm trying to do something that should be very common: add/edit a bunch of related models in a single form. For example:
Visitor Details:
Select destinations and activities:
Miami [] - swimming [], clubbing [], sunbathing[]
Cancun [] - swimming [], clubbing [], sunbathing[]
My models are Visitor, Destination and Activity, with Visitor having a ManyToMany field into Destination through an intermediary model, VisitorDestination, which has the details of the activities to be done on the destination (in itself a ManyToMany field into Activity).
Visitor ---->(M2M though VisitorDestination) -------------> Destination
|
activities ---->(M2M)---> Activity
Note that I don't want to enter new destination / activity values, just choose from those available in the db (but that's a perfectly legit use of M2M fields right?)
To me this looks like an extremely common situation (a many to many relation with additional details which are a FK or M2M field into some other model), and this looks like the most sensible modelling, but please correct me if I'm wrong.
I've spent a few days searching Django docs / SO / googling but haven't been able to work out how to deal with this. I tried several approaches:
Custom Model form for Visitor, where I add multiple choice fields for Destination and Activity. That works ok if Destination and Activity could be selected independently, but here they are correlated, ie I want to choose one or several activities for each destination
Using
inlineformset_factory
to generate the set of destination / activities forms, withinlineformset_factory(Destination, Visitor)
. This breaks, because Visitor has a M2M relation to Destination, rather than a FK.Customizing a plain formset, using
formset_factory
, egDestinationActivityFormSet = formset_factory(DestinationActivityForm, extra=2)
. But how to designDestinationActivityForm
? I haven't explored this enough, but it doesn't look very promising: I don't want to type in the destination and a list of activities, I want a list of checkboxes with the labels set to the destination / activities I want to select, but theformset_factory
would return a list of forms with identical labels.
I'm a complete newbie with django so maybe the solution is obvious, but I find that the documentation in this area is very weak - if anyone has some pointers to examples of use for forms / formsets that would be also helpful
thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
最后,我选择在同一视图中处理多个表单,一个用于访问者详细信息的访问者模型表单,然后是每个目的地的自定义表单列表。
事实证明,在同一视图中处理多个表单非常简单(至少在本例中,不存在跨字段验证问题)。
我仍然感到惊讶的是,中间模型没有对多对多关系的内置支持,并且在网络中查找时我发现没有直接引用它。我会发布代码,以防它对任何人有帮助。
首先是自定义表单:
我通过传递
Visitor
和Destination
对象(以及为方便起见而在外部计算的“已访问”标志)来自定义每个表单,我使用布尔字段来允许用户选择每个目的地。该字段称为“已访问”,但我将标签设置为目的地,以便它可以很好地显示。
这些活动由通常的 MultipleChoiceField 处理(我使用自定义的小部件来获取要在表格上显示的复选框,非常简单,但如果有人需要的话可以发布它)
然后查看代码:
我只需在列表中收集我的目标表单,然后将此列表传递给我的模板,以便它可以迭代它们并显示它们。只要您不忘记为构造函数中的每个前缀传递不同的前缀,它就可以很好地工作。
我会将问题保留几天,以防有人有更干净的方法。
谢谢!
In the end I opted for processing multiple forms within the same view, a Visitor model form for the visitor details, then a list of custom forms for each of the destinations.
Processing multiple forms in the same view turned out to be simple enough (at least in this case, where there were no cross-field validation issues).
I'm still surprised there is no built-in support for many to many relationships with an intermediary model, and looking around in the web I found no direct reference to it. I'll post the code in case it helps anyone.
First the custom forms:
I customize each form by passing a
Visitor
andDestination
objects (and a 'visited' flag which is calculated outside for convenience)I use a boolean field to allow the user to select each destination. The field is called 'visited', however I set the label to the destination so it gets nicely displayed.
The activities get handled by the usual MultipleChoiceField (I used I customized widget to get the checkboxes to display on a table, pretty simple but can post it if somebody needs that)
Then the view code:
I simply collect my destination forms in a list and pass this list to my template, so that it can iterate over them and display them. It works well as long as you don't forget to pass a different prefix for each one in the constructor
I'll leave the question open for a few days in case some one has a cleaner method.
Thanks!
因此,正如您所看到的,有关 inlineformset_factory 的一件事是它需要两个模型 - 父模型和子模型,子模型与父模型具有外键关系。如何将额外的数据动态传递到表单,以获取中间模型中的额外数据?
我如何做到这一点是通过使用 curry:
表单类“ChildModelForm”需要有一个 init 覆盖,从参数中添加“some_extra_model”对象:
希望这可以帮助您走上正确的轨道。
So, as you've seen, one of the things about inlineformset_factory is that it expects two models - a parent, and child, which has a foreign key relationship to the parent. How do you pass extra data on the fly to the form, for extra data in the intermediary model?
How I do this is by using curry:
The form class "ChildModelForm" would need to have an init override that adds the "some_extra_model" object from the arguments:
Hope that helps get you on the right track.
从 django 1.9 开始,支持将自定义参数传递给 formset 表单:
https://docs .djangoproject.com/en/1.9/topics/forms/formsets/#passing-custom-parameters-to-formset-forms
只需将 form_kwargs 添加到您的FormSet 初始化如下:
From django 1.9, there is a support for passing custom parameters to formset forms :
https://docs.djangoproject.com/en/1.9/topics/forms/formsets/#passing-custom-parameters-to-formset-forms
Just add form_kwargs to your FormSet init like this :