Django:在表单中嵌套表单(递归...)

2 投票
4 回答
644 浏览
提问于 2025-04-18 13:07

我很喜欢Django的表单库,但如果一个表单可以包含其他表单,那就更好了。

我心中的理想是这样的:

  • 我有一个表单,它的表现和普通表单一样,比如叫做 SuperForm 的类。
  • SuperForm 可以包含几个普通表单,甚至可以包含(递归的)SuperForms
  • 你可以把它和数据绑定(让它变成绑定状态),调用 is_valid() 等等……

这样在Django里或者通过外部应用实现这个功能可能吗?

更新

我发现很多人没有理解我想要的东西。是我的错,我没有给出具体的使用场景。

使用场景:一个页面应该允许用户更新他们的电子邮件和电话号码。电子邮件来自 django.contrib.auth,而电话号码来自我们自定义的模型。

这两个输入应该放在一个单独的 <form> 标签里。因为 ModelForm 使用起来很简单,所以我不想手动自己创建一个表单。

我想要一个容器,里面包含 django.contrib.auth.models.UserModelForm 和我们自定义模型的 ModelForm

我不想自己去遍历这两个表单(在其他使用场景中可能会有更多的表单),检查它们是否有效。

如果我在这个容器上调用 is_valid()save(),就会自动调用表单对应的方法。

4 个回答

-1

我觉得你对表单的理解可能有些偏差。

表单其实就是用来输入数据的。至于这些数据怎么处理,那就看你自己了。

当然,你可以在表单上运行 is_valid,这样可以检查你指定的模型表单。更棒的是,你可以在同一个表单上检查多个模型表单。模型表单需要的数据会被处理,而多余的数据会被忽略。如果 is_valid 检查失败,你仍然可以像往常一样把数据返回去,让用户进行修改。

0

乍一看,你的想法似乎有点复杂。首先要问的是:“为什么需要这样的功能?”99%的任务可以用Django自带的工具来解决,剩下的1%就只能硬编码了。另外,我还可以推测,提出这样想法背后的问题也很复杂,普通用户可能很难理解。

1

我不太确定你想要实现什么,但我曾经遇到过关于动态表单的问题。

如果你有一个表单(或者叫ModelForm,或者其他你需要的东西),你可以在你的视图中根据需要初始化这个表单多次。

比如说,如果你有一个叫MyForm的表单,你可以在视图中这样做:

...        ...
form1 = MyForm(...)
form2 = MyForm(...)
form3 = MyForm(...)
...         ...

然后你可以把所有这些表单发送到模板中。

这些表单的数量不需要是固定的,你可以把多个“动态”的表单放到一个列表里,然后把这个表单列表发送到模板中,按需管理它们。

如果你能多解释一下你的情况,以及你为什么想要实现这个功能,会对你和帮助你的人更有帮助,因为我的回答可能对你没用。

无论如何,我强烈建议你查看一下Django FormSets,因为这是在一个模板中生成和管理动态表单的最佳方式。


你在什么情况下需要这种“动态”表单?

你想获取什么样的信息?

你是在尝试动态创建对象吗?

你是想根据某些信息来决定表单的数量吗?

你打算如何在你的模板或视图中管理这些“动态”表单?

3

你可以试试这个叫做 django-composite-form 的工具。使用它,你可以写出像下面这样的代码:

这是从这个工具包里附带的示例中摘录的

from django import forms
from django.contrib.auth.forms import UserCreationForm
from composite_form.forms import CompositeForm
from example.models import Profile


class BaseProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        exclude = ("user")


class ProfileForm(CompositeForm):
    form_list = [UserCreationForm, BaseProfileForm]

    def clean_address(self):
        return "blah"

    def save(self, commit=True):
        if not self.is_valid():
            raise ValueError("Invalid form")
        user_form = self.get_form(UserCreationForm)
        user = user_form.save()
        profile_form = self.get_form(BaseProfileForm)
        profile_form.instance.user = user
        return profile_form.save()

撰写回答