## 11.5 了解表单验证如何工作
表单验证是Django的诸多领域之一,了解其内部的运作将会大幅度的提高你的代码质量。让我们花一些时间去钻研表单验证并且讲述一些要点。
当你调用form.is_valid()时,很多事件在表面之后发生。下列事件发生在这个工作流里:
1.如果这个表单含有绑定数据,form.is_valid()会调用form.full_clean()方法。
2.form.full_clean在表单字段中迭代并且验证每个字段:
a.数据进入到表单字段内通过to_python()方法被强制转为Python代码或者产生一个ValidationError错误。
b.数据针对特殊的表单字段规则进行验证,包括自定义验证器。失败的话会产生一个ValidationError错误。
c.如果在表单中存在任何自定义clean_
3.form.full_clean()执行 form.clean()方法。
4.如果是模型表单的实例,form._post_clean()将会做如下事情:
a.设置模型表单的数据到模型的实例中,不管是否form.is_valid()是True还是False。
b.调用模型的clean()方法。作为参考,存储一个模型实例通过ORM不会调用模型的clean()方法。
如果这看起来很复杂,请记住,在实践中它会变得简单些,而且所有这些功能都让我们真正理解输入数据中发生了什么。在下一节的例子应该有助于解释这一步。
11.5.1 模型表单数据被存储到表单实例,然后到模型实例
我们喜欢把这个叫做WHAT?!?的表单验证。(原文:We like to call this the WHAT?!? of form validation.可能我的电子版错误,如有错误请指正。)乍看起来,表单数据被安放到表单实例中看起来像是一个BUG。但是这不是BUG,这是预期行为。
在一个模型表单中,表单数据在两个不同的步骤中被存储:
1.首先,表单数据被存储到表单实例。
2.然后,表单数据被存储到模型实例。
因为模型表单不被存储到模型实例直到它们通过form.save()方法被激活,我们可以利用这种分离的优势形成一个有用的功能。
举个例子,或许你需要对一个表单抓捕提交失败的细节,保存用户提供的表单数据以及预期模型实例更改。
一个简单的,也许是简单的,捕捉数据的方式如下。首先,我们创建一个失败表单的历史模型在core/models.py中:
EXAMPLE 11.6
# core/models.py
from django.db import models
class ModelFormFailureHistory(models.Model):
form_data = models.TextField()
model_data = models.TextField()
接着,我们添加下面的代码到flavors/views.py的FlavorActionMixin:
EXAMPLE 11.7
# flavors/views.py
import json
from django.contrib import messages
from django.core import serializers
from core.models import ModelFormFailureHistory
class FlavorActionMixin(object):
@property
def success_msg(self):
return NotImplemented
def form_valid(self, form):
messages.info(self.request, self.success_msg)
return super(FlavorActionMixin, self).form_valid(form)
def form_invalid(self, form):
"""Save invalid form and model data for later reference."""
"""保存无效的格式和模型数据以供以后参考。"""
form_data = json.dumps(form.cleaned_data)
model_data = serializers.serialize("json",
[form.instance])[1:-1]
ModelFormFailureHistory.objects.create(
form_data=form_data,
model_data=model_data
)
return super(FlavorActionMixin,
self).form_invalid(form)
如果你还记得, form_invalid()被调用在一个错误表单数据的验证失败之后,当它在这个例子中被调用时,表单清理数据和保存到数据库的最终数据都被保存为一个ModelFormFailureHistory记录。