在单个Django ModelForm中使用多个模型?
在Django中,能不能把多个模型放到一个ModelForm
里面呢?我想做一个个人资料编辑的表单,所以需要同时包含用户模型(User model)和用户资料模型(UserProfile model)的一些字段。目前我用的是两个表单,像这样:
class UserEditForm(ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name")
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
fields = ("middle_name", "home_phone", "work_phone", "cell_phone")
有没有办法把这两个表单合并成一个,还是说我只能自己创建一个表单,然后手动处理数据库的加载和保存呢?
6 个回答
5
我在我的项目中使用了 django betterforms 的 MultiForm 和 MultiModelForm。不过,代码还有改进的空间。例如,它依赖于 django.six,而这个在 3.+ 版本中是不支持的,但这些问题都能很容易地解决。
12
你可以试试这段代码:
class CombinedFormBase(forms.Form):
form_classes = []
def __init__(self, *args, **kwargs):
super(CombinedFormBase, self).__init__(*args, **kwargs)
for f in self.form_classes:
name = f.__name__.lower()
setattr(self, name, f(*args, **kwargs))
form = getattr(self, name)
self.fields.update(form.fields)
self.initial.update(form.initial)
def is_valid(self):
isValid = True
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
if not form.is_valid():
isValid = False
# is_valid will trigger clean method
# so it should be called after all other forms is_valid are called
# otherwise clean_data will be empty
if not super(CombinedFormBase, self).is_valid() :
isValid = False
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
self.errors.update(form.errors)
return isValid
def clean(self):
cleaned_data = super(CombinedFormBase, self).clean()
for f in self.form_classes:
name = f.__name__.lower()
form = getattr(self, name)
cleaned_data.update(form.cleaned_data)
return cleaned_data
使用示例:
class ConsumerRegistrationForm(CombinedFormBase):
form_classes = [RegistrationForm, ConsumerProfileForm]
class RegisterView(FormView):
template_name = "register.html"
form_class = ConsumerRegistrationForm
def form_valid(self, form):
# some actions...
return redirect(self.get_success_url())
117
你可以在一个 <form>
的 HTML 元素里面同时显示两个表单。然后在视图中分别处理这两个表单。这样你仍然可以使用 form.save()
,不需要自己去处理数据库的加载和保存。
在这种情况下你可能不需要这样做,但如果你要使用的表单有相同的字段名称,可以看看 Django 表单中的 prefix
参数。我在这里回答过一个关于这个的问题 这里。