问题描述
我有一个有效的inlineformset。我试图添加第二个提交按钮,当单击该按钮时,将检查每个内联表单中的特定字段是否已填写,即,仅当单击第二个提交按钮时,此字段才成为必填字段。
问题是,当我单击第二个提交按钮时,不会出现验证错误,并且表单似乎仍然可以提交。我认为问题出在我的视野之内,即form_valid。我不确定if form.is_valid()
失败时需要返回什么。
我正在自学编码,因此非常感谢您的帮助或指导。
Forms.py
class response_form_draft(forms.ModelForm):
class Meta:
name = response
exclude = ['id_question','order']
def __init__(self,*args,**kwargs):
super(response_form_draft,self).__init__(*args,**kwargs)
self.helper = FormHelper()
self.helper.form_show_labels = False
class response_form_final(forms.ModelForm):
class Meta:
name = response
exclude = ['id_question',**kwargs):
super(response_form_final,**kwargs)
self.helper = FormHelper()
self.helper.form_show_labels = False
def clean(self):
data = self.cleaned_data
resp = data['response']
if resp == "":
raise forms.ValidationError(('must not be blank'))
checklist_formset_draft = inlineformset_factory(checklist,response,form = response_form_draft,extra=0,can_delete=False,widgets={'comments': forms.Textarea(attrs={'cols': 7,'rows': 3,'style':'resize:none'})
})
checklist_formset_final = inlineformset_factory(checklist,form = response_form_final,'style':'resize:none'}),'response': forms.TextInput(attrs={'required':True})
})
Views.py
class ChecklistUpdateView(LoginrequiredMixin,UpdateView):
login_url = '/user/login'
model = checklist
form_class = checklist_form
success_url = reverse_lazy('checklist:checklist_list')
def get_context_data(self,**kwargs):
data = super(ChecklistUpdateView,self).get_context_data(**kwargs)
if self.request.POST:
if 'complete' in self.request.POST:
print("complete")
data['question'] = checklist_formset_final(self.request.POST,instance=self.object)
else:
print("draft")
data['question'] = checklist_formset_draft(self.request.POST,instance=self.object)
else:
data['question'] = checklist_formset_draft(instance=self.object)
return data
def form_valid(self,form):
context = self.get_context_data()
question = context['question']
with transaction.atomic():
self.object = form.save(commit=False)
self.object.last_edit_by = str(self.request.user)
self.object.last_edit_date = timezone.Now()
if question.is_valid():
question.instance = self.object
question.save()
return super(ChecklistUpdateView,self).form_valid(form)
HTML模板
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<form method="post">
{% csrf_token %}
<h1>{{ object.id_template.title }}</h1>
{{ form.errors }}
{{ form.entity|as_crispy_field }}
{{ form.date_created.as_hidden }}
{{ form.created_by.as_hidden }}
{{ form.id_template.as_hidden }}
{{ form.status.as_hidden }}
<div class="card">
<table id="table_id" class="table">
<tbody>
{{ question.management_form }}
{% for form in question.forms %}
{{ formset.errors }}
{{ form.non_field_errors }}
{% if forloop.first %}
<thead class="thead-dark">
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
<th></th>
</tr>
</thead>
{% endif %}
<tr class="{% cycle row1 row2 %} formset_row">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{% if field.label == "Question" %}
<p>{{ form.question.value }}</p>
{{ field.as_hidden }}
{% elif field.label == "Response" %}
{{ field.as_hidden }}
<button id="Yes.{{ forloop.parentloop.counter0 }}" row="{{ forloop.parentloop.counter0 }}" class="ans {{ forloop.parentloop.counter0 }} btn btn-dark right">Yes</button>
<button id="No.{{ forloop.parentloop.counter0 }}" row="{{ forloop.parentloop.counter0 }}" class="ans {{ forloop.parentloop.counter0 }} btn btn-dark right">No</button>
<button id="N/a.{{ forloop.parentloop.counter0 }}" row="{{ forloop.parentloop.counter0 }}" class="ans {{ forloop.parentloop.counter0 }} btn btn-dark right">N/a</button>
{% else %}
{{ field|as_crispy_field }}
{% endif %}
</td>
{% endfor %}
<td> </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{{ form.comments|as_crispy_field }}
{{ form.audit|as_crispy_field }}
<div class="form-submit-row" id="submit-row">
<input class="btn btn-dark right" name="draft "type="submit" value="Save draft">
<input class="btn btn-dark right" name="complete" type="submit" value="Complete">
<a href="{% url 'checklist:checklist_delete' pk=object.id %}" class="btn btn-danger right">Delete</a>
</div>
</form>
<br><br>
</div>
解决方法
表单有效时,
form_valid
被激活。 django在类视图中自动检查checklist_form
的有效性,而无需验证表单集。您可以在form_valid
和form_invalid
中添加自定义验证,但我会采取另一种方式。我会将formset放入您的基本表单(checklist_form)
类似的东西:
class checklist_form(forms.ModelForm):
def __init__(*args,**kwargs):
self.question= kwargs.pop("question")
super()__.init__(*args,**kwargs)
def clean(self):
cleaned_data = super().clean()
if not self.question.is_valid():
self.add_error(None,"Have some formset errors")
return cleaned_data
now表单仅在formset也有效的情况下才有效。然后在您的ChecklistUpdateView
中,将创建表单集放入get_form_kwargs
def get_form_kwargs(self):
data = super().get_form_kwargs()
if self.request.POST:
if 'complete' in self.request.POST:
data['question'] = checklist_formset_final(self.request.POST,instance=self.object)
else:
data['question'] = checklist_formset_draft(self.request.POST,instance=self.object)
else:
data['question'] = checklist_formset_draft(instance=self.object)
return data
在那之后,您需要在html模板中使用form.question
而不是question