我最近通过继承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可以实现多表单页面吗?我不知道如何处理它,无论是在将多个表单传递给View(例如,另一个UpdateAccountForm和UpdateBillingForm),还是区分哪个表单已提交/验证?什么是最好的方式?
答案 0 :(得分:14)
嗯,这里有什么值得的,最终对我有用,使用通用视图。
1)我在页面上为每个单独的表单添加了一个隐藏的输入字段(名为“action”)。例如,这是用于更新用户信息的表单,其中包含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)在我的View逻辑中,我可以通过应用前缀(每个其他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)
似乎运作良好,希望这是正确的方法(?)
答案 1 :(得分:0)
你可以编写一个简单的python类来模仿Form
API(至少是有用的部分)并包装你的三个表单。检测已提交的表单只是在每个表单中添加带有表单标识符的隐藏输入(提示:使用表单的前缀并使用与标识符相同的前缀)。
另一个解决方案是使用一个简单的基于函数的视图,但即便如此,就我而言,我仍然使用相同的“表单包装”模式。