Django:使用 FormView 时可能有多种形式?

Posted

技术标签:

【中文标题】Django:使用 FormView 时可能有多种形式?【英文标题】:Django: Multiple forms possible when using FormView? 【发布时间】:2014-02-11 14:45:43 【问题描述】:

我最近通过继承FormView 学习了Django 表单,其中所需的表单被分配给FormView.form_class 属性。当表单验证时,将调用form_valid() 方法(针对该表单)。例如:

from accounts.forms import SignUpForm, UpdateAccountForm, UpdateBillingForm

class SignUpView(FormView):
    form_class = SignUpForm

    def form_valid(self, form):
    # code when form validates...

但是,我现在有一种情况,我需要在一个页面上显示三个独特的表单(一次只有一个表单对用户可见)。所以,我想在同一个视图中处理它们。

是否可以使用 FormView 实现多表单页面?我不确定如何处理它,包括将多个表单传递给视图(例如另一个 UpdateAccountForm 和 UpdateBillingForm),以及区分哪个已提交/验证?最好的方法是什么?

【问题讨论】:

看起来 FormView 不可能。根据这些answers,应该使用通用视图,并添加前缀 (?) 我刚刚写了一个工具来做这个确切的事情,到目前为止只有部分记录,但是类 MultFormView 只是几行代码来处理你正在尝试做的事情github.com/dm03514/django-cbv-toolkit 【参考方案1】:

嗯,对于我来说,使用通用视图最终对我有用。

1) 我为页面上的每个单独的表单添加了一个隐藏的输入字段(名为“操作”)。比如这个是更新用户信息的表单,拉入了UserForm:

<form action='/account/' method='post'>% csrf_token %
   <input type='hidden' name='action' value='edit_user'> 
    user_form.as_p 
   <input type='submit' value='Update'>
</form>

2) 在我的视图逻辑中,我可以通过应用前缀来区分表单(根据其他 SO 帖子和 Django docs)。然后,根据传入的“操作”,我只将适用的表单绑定到 POST 请求(因此验证不会应用于所有表单)。就我而言,我在 forms.py 中定义了两个表单,UserForm 和 BillingForm:

from django.views.generic.edit import View
from django.shortcuts import render
from django.http import HttpResponse

from accounts.forms import UserForm, BillingForm

class AccountView(View):

    def get(self, request):
        # code for GET request...

    def post(self, request):
        #instantiate all unique forms (using prefix) as unbound
        user_form    = UserForm(prefix='user_form')
        billing_form = BillingForm(prefix='billing_form')

        # determine which form is submitting (based on hidden input called 'action')
        action = self.request.POST['action']

        # bind to POST and process the correct form
        if (action == 'edit_user'):
            user_form = UserForm(request.POST, prefix='user_form')
            if user_form.is_valid():
                # user form validated, code away..

        elif (action == 'edit_billing'):
            billing_form = BillingForm(request.POST, prefix='billing_form')
            if billing_form.is_valid():
                # billing form validated, code away..

        # prep context
        context = 
            'user_form':    user_form,
            'billing_form': billing_form,
        
        return render(request, 'accounts/account.html', context) 

似乎运作良好,希望这是正确的方法(?)

【讨论】:

为什么表单实例化了两次,两次都带有前缀? @problemofficer 我能看到的唯一原因是如果 if/elif 语句不运行,页面将再次使用表单呈现。基本上好像表格无效。【参考方案2】:

您可以编写一个模仿Form API 的普通python 类(至少是有用的部分)并包装您的三个表单。检测已提交的表单只需在每个表单中添加一个带有表单标识符的隐藏输入(提示:为您的表单使用前缀并使用相同的前缀作为标识符)。

另一种解决方案是改用简单的基于函数的视图,但即便如此,就我而言,我仍然会使用相同的“表单包装器”模式。

【讨论】:

以上是关于Django:使用 FormView 时可能有多种形式?的主要内容,如果未能解决你的问题,请参考以下文章

将参数传递给FormView Django中的表单

使用jquery post时未调用django formview中的post函数

django - 使用 FormView 和 ModelForm 更新模型

重定向到 django FormView 中的下一个 URL

Django:如何使用FormView和ajax将对象保存到数据库?

python 基于FormView类的django视图示例