具有来自两个不同模型的字段的 Django 表单

Posted

技术标签:

【中文标题】具有来自两个不同模型的字段的 Django 表单【英文标题】:Django form with fields from two different models 【发布时间】:2015-03-14 03:22:15 【问题描述】:

我需要显示一个表单,其中包含来自 2 个不同模型的多个字段。 表单将仅包含模型中的部分字段,并且将使用清晰的表单进行布局。

我的模型:

class Company(BaseModel):
    title = models.CharField(_('Company'), max_length=128)
    domain = models.CharField(_('Domain'), max_length=128)
class Account(BaseModel):
    company = models.ForeignKey(Company)
    user = models.OneToOneField(User)
    role = models.CharField(_('Role'), choices=ROLES, default='member', max_length=32)

我想在表单中显示的字段: 公司名称、用户名、用户姓氏、用户电子邮件

有可能吗?我该怎么做?

【问题讨论】:

您可以在视图中传递这两种形式 手动制作表格。 class MyCustomForm(forms.Form)。您可以在其中包含任何您想要的字段,不限于数据模型。 @Kakar 离这里最近。此页面上的其他答案涉及放弃使用 ModelForms 的好处。虽然这有时是最好的方法 - 创建两个模型表单(呈现为单个 html 表单)可能更“Djangonic” - 我会尽快尝试写出正确的答案。 【参考方案1】:

在你的 forms.py 中

from django import forms


class YourForm(forms.Form):
    title = forms.CharField()
    first_name = forms.CharField()
    last_name = ...

在你的意见中.py

from forms import YourForm
from django import views
from models import Company, Account

class YourFormView(views.FormView)
    template_name = 'some_template.html'
    form_class = YourForm
    success_url = '/thanks/'

    def form_valid(self, form):
        title = form.cleaned_data['title']
        ...
        # do your processing here using Company and Account
        # i.e. company = Company.objects.create(title=title, ...)
        #      account = Account.objects.get_or_create(
        #      user=..., company=company ...)
        #      ... more processing
        #
        # Call company.save() and account.save() after adding
        # your processed details to the relevant instances
        #  and return a HttpResponseRedirect(self.success_url)

    def is_valid(self):
        # don't forget to validate your fields if need be here

像往常一样,这些文档非常有帮助。 https://docs.djangoproject.com/en/1.7/topics/forms/

【讨论】:

【参考方案2】:

此页面上的其他答案涉及放弃模型表单的好处,并且可能需要复制您免费获得的一些功能。

真正的关键是要记住一个 html 表单!= 一个 django 表单。您可以将多个表单包装在一个 html 表单标签中。

因此,您可以创建两个模型表单并在模板中呈现它们。除非某些字段名称发生冲突,否则 Django 将处理每个表单所属的 POST 参数 - 在这种情况下,当您实例化每个表单时,会为每个表单指定一个唯一的前缀。

表格:

class CompanyForm(forms.ModelForm):
    class Meta:
        fields = [...]
        model = Company

class AccountForm(forms.ModelForm):
    class Meta:
        fields = [...]
        model = Account

查看:

if request.method == 'POST':

    company_form = CompanyForm(request.POST)
    account_form = AccountForm(request.POST)

    if company_form.is_valid() and account_form.is_valid():

        company_form.save()
        account_form.save()
        return HttpResponseRedirect('/success')        

    else:
        context = 
            'company_form': company_form,
            'account_form': account_form,
        

else:
    context = 
        'company_form': CompanyForm(),
        'account_form': AccountForm(),
    

return TemplateResponse(request, 'your_template.html', context)

模板:

<form action="." method="POST">
    % csrf_token %
     company_form.as_p 
     account_form.as_p 
    <button type="submit">
</form>

【讨论】:

+1 为您提供干净的答案。这是 Django 的做事方式。唯一的问题是您不能插入来自不同模型的字段。如果您可以扩展如何在模板渲染中插入来自不同模型的字段,我将不胜感激。 @OmarGonzales 要插入,我们需要分别渲染每个字段(而不是使用类似 company_form.as_p 的东西) 有没有办法在基于类的视图中实现这一点? @PavelShlepnev 您所说的基于类的视图是什么意思。无论是功能视图还是类视图,逻辑都是相同的。你可以在你的类视图中编写一个 get 和 post 方法,其余的都是一样的

以上是关于具有来自两个不同模型的字段的 Django 表单的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 中制作不同的注册表单?

如何在 Django 中从 2 个不同的模型对象创建表单对象?

仅具有查看权限的 Django 模型表单将所有字段排除在外

使用 CBV 在 Django 中的一个视图/模板中的两个模型表单

如何使用来自两个不同表的旧信息自动填充编辑表单?

具有未知数量的复选框字段和多个操作的 Django 表单