form_invalid()
是Django视图函数中,处理表单验证失败时的方法。当表单验证失败时,Django自动将验证引发的异常重定向到该函数。具体来说,这个函数会显示表单验证失败信息,和用于填写过程的表单。它可以对错误进行自定义处理,并在需要时,对表单数据提供补救。
通常,form_invalid()
方法用于显示错误信息并重新展示前置表单,以便填写者可以更正错误。另外,我们也可以选择数据恢复、错误信息字段高亮、记录错误信息、发送邮件等操作。
以下是 form_invalid()
的基本使用方法的攻略:
- 重写
form_invalid()
方法
我们可以选择在视图类中重写 form_invalid()
方法来实现我们自己的逻辑。Django将在意料之外的错误发生时调用此方法。通过这个方法,我们可以获取到当前视图处理的表单,并进行一些自定义逻辑。
示例:
from django.views.generic.edit import FormView
from .forms import ContactForm
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
def form_invalid(self, form):
# Do some business logic here
return super().form_invalid(form)
- 处理表单错误
Django提供了一种简便方式来验证表单数据。使用 is_valid()
方法可以验证表单数据。如果表单无效,可以使用 form.errors
字典对象获取到验证不通过字段的错误信息。
示例:
def form_invalid(self, form):
error_message = 'Please correct the errors below.'
return self.render_to_response(
self.get_context_data(
error_message=error_message,
form=form
)
)
在这个例子中,当表单无效时,form_invalid()
函数将构建错误信息,并添加到上下文渲染器 get_context_data()
中呈现出来。
- 渲染表单观察错误
如果表单数据在表单验证期间无效,Django经常会将表单视为在当前请 求上下文中已经存在的一个对象,并为您呈现此表单。当表单无效时,可以使用form.errors
获取错误信息,并在模板中使用必要的格式呈现。
{% if form.errors %}
<div class="alert alert-danger">
<strong>Please correct the following errors:</strong>
<ul>
{% for field in form %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
上面 HTML 代码将会查找表单中的错误信息,并呈现它们。如果表单有效,则不会呈现该消息。
- 错误隐藏/显示
对于一些表单域,您可能希望将错误消息嵌入到表单控件的HTML中。可以使用以下代码将错误信息嵌入到HTML中。
{% for field in form %}
{% if field.errors %}
<div class="form-group has-error">
{% for error in field.errors %}
<span class="help-block">{{ error }}</span>
{% endfor %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% endfor %}
在这个例子中,假设表单控件通常渲染为<input type="text">
。如果验证错误发生,则包装div类为has-error
的CSS类,并在现有输入中嵌入错误信息,以显示错误发送的字段。发生验证错误时,还可以在输入控件中添加 required
或 aria-invalid
属性。
- 记录验证错误
当表单验证失败时,我们可以选择记录错误。这可以通过保存错误消息,将其写入日志,或在指定外部服务上发送电子邮件等方式实现。
import logging
log = logging.getLogger(__name__)
def form_invalid(self, form):
log.error(
'Unexpected form validation error in contact view; '
'errors %s',
form.errors.as_json(),
exc_info=True,
)
return super().form_invalid(form)
在此情况下,我们在视图中记录了错误消息。此日志记录是在请求上下文中发生的,并包含错误消息的JSON表示。当出现错误时,将指定sys.exc_info()事件记录传递给日志记录系统。
这是一个示例视图类:
from logging import getLogger
from typing import Type
from django.views.generic.edit import FormView
from django.http import HttpResponse
from .forms import ContactForm
log = getLogger(__name__)
class LoggingContactFormView(FormView):
template_name = 'contact.html'
form_class = ContactForm
def form_invalid(self, form):
log.exception(
'Unexpected form validation error in contact view; '
'errors %s',
form.errors.as_json(),
exc_info=True
)
return super().form_invalid(form)
def form_valid(self, form):
log.info(
'Form submission with valid data %s', form.cleaned_data
)
return HttpResponse('Thanks for your submission')
- 错误恢复
在某些情况下,验证失败后我们可以选择还原现有表单中可用的数据,以便填写者可以更轻松地纠正其问题。
def form_invalid(self, form):
context = self.get_context_data(
form=form,
)
try:
previous_values = self.request.POST.dict()
previous_values.pop('csrfmiddlewaretoken')
context.update({
'request_values': previous_values
})
except Exception as e:
log.exception(e)
return self.render_to_response(context=context)
在此代码段中,当表单无效时, form_invalid()
还会将先前在表单中填写的值保存到HTML页面中。在上面的实现中,我们可以在重新渲染表单之前检测到并删除 POST
请求中的 csrfmiddlewaretoken
值。然后,我们将先前的值作为上下文变量传递到表单中的输入字段中。
参考文档:
- https://docs.djangoproject.com/en/3.2/ref/class-based-views/mixins-forms/#django.views.generic.edit.FormMixin.form_invalid
- https://docs.djangoproject.com/en/3.2/topics/forms/#rendering-form-errors