使用表单| crispy过滤器在视图中放置2个表单时,此答案可在单个视图中处理2个表单:Proper way to handle multiple forms on one page in Django我收到this错误。
views.py:
def test_form(request):
if not request.user.is_authenticated():
return redirect(settings.LOGIN_URL)
title = 'test form'
row_control_form = RowControlForm(request.POST or None)
entry_form = EntryForm(request.POST or None)
context = {
'title': title,
'row_control_form': row_control_form,
'entry_form': entry_form,
}
if 'row_control_submit' in request.POST:
if row_control_form.is_valid():
row_control_form.save()
if 'entry_submit' in request.POST:
if entry_form.is_valid():
entry_form.save()
return render(request, "timesheet/test_form.html", context)
forms.py
class RowControlForm(forms.ModelForm):
class Meta:
model = RowControl
fields = ['month_control_record', 'department', 'activity', 'notes']
def clean(self):
cleaned_data = self.cleaned_data
# Ensures row is unique
try:
RowControl.objects.get(month_control_record=cleaned_data['month_control_record'],
department=cleaned_data['department'],
activity=cleaned_data['activity'],
notes=cleaned_data['notes'])
except RowControl.DoesNotExist:
pass
else:
raise ValidationError('This row already exists')
# Always return cleaned data
return cleaned_data
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['row_control', 'date', 'hours']
def clean(self):
cleaned_data = self.cleaned_data
# Ensures data is unique (only 1 hours entry for each date and row_control)
try:
Entry.objects.get(row_control=cleaned_data['row_control'],
date=cleaned_data['date'])
except Entry.DoesNotExist:
pass
else:
raise ValidationError('This entry already exists')
# Always return cleaned data
return cleaned_data
test_form.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-md-6 col-md-offset-3">
<h1 class="page-header"> Form Test </h1>
<form method="POST" action="{{ request.path }}">
{% csrf_token %}
{{ row_control_form|crispy }}
<button class="btn btn-primary" type="submit" value="Submit" name="row_control_submit" ><i class="fa fa-lg fa-floppy-o"></i> Save</button> </form>
</br>
</div>
<div class="col-md-6 col-md-offset-3">
<h1 class="page-header"> Form Test </h1>
<form method="POST" action="{{ request.path }}">
{% csrf_token %}
{{ entry_form|crispy }}
<button class="btn btn-primary" type="submit" value="Submit" name="entry_submit" ><i class="fa fa-lg fa-floppy-o"></i> Save</button> </form>
</br>
</div>
{% endblock %}
为错误提供上下文: forms.py的第42行是:
Entry.objects.get(row_control=cleaned_data['row_control'],
编辑:进一步的调查表明问题是,无论按下哪个提交按钮,两个表格验证都在运行,提交RowControlForm的有效数据时的request.POST是:
<QueryDict: {'csrfmiddlewaretoken': ['HffmmbI31Oe0tItYDfYC4MoULQHL0KvF'], 'notes': ['Cool'], 'row_control_submit': ['Submit'], 'month_control_record': ['1'], 'department': ['1'], 'activity': ['1']}>
因此,entry_submit不在request.POST中,并且该验证不应该运行吗?
答案 0 :(得分:1)
首先,您需要修复表单clean
方法的这一行
def clean(self):
...
Entry.objects.get(row_control=cleaned_data['row_control'],
您不能认为row_control
将在cleaned_data
中。您需要添加检查if 'row_control' in cleaned_data
或捕获KeyError
,然后相应地更新方法的其余部分。您应该解决此问题,即使您在一个页面上放置多个表单之前没有看到此错误。通过从POST请求中保留一个值,不应该导致500服务器错误。即使页面上只有一个表单,用户也可以这样做。
两种表单都在运行验证,因为无论按下哪个提交按钮,都要使用发布数据实例化两个表单。
row_control_form = RowControlForm(request.POST or None)
entry_form = EntryForm(request.POST or None)
您只应将POST数据用于您要提交的表单。
row_control_form = RowControlForm()
entry_form = EntryForm()
if 'row_control_submit' in request.POST:
row_control_form = RowControlForm(request.POST)
if row_control_form.is_valid():
if 'entry_submit' in request.POST:
entry_form = EntryForm(request.POST)
if entry_form.is_valid():
entry_form.save()
最后,在用户成功提交有效表单后重定向是一种很好的做法。