在Django中,对数据进行校验有两种方式:一种是通过Form中校验,一种是通过Model校验。在次,我对Model中的校验方法做下记录。
所有内容都是基于Django1.10的官网文档整理而来
validating objects
数据校验的触发:
Model中的校验是通过调用Model.full_clean()
方法来执行的。包括在Form中也会对objects进行校验,也是通过调用Model.full_clean()
的方式来进行的。但是,通常的情况下我们并不需要自己调用Model.full_clean()
方法。
什么时候需要调用full_clean()
当你使用ModelForm的时候,Model.full_clean()
将会在你调用is_valid()
方法的时候对ModelForm中所有的field进行校验。只有当你想要自己特别的处理校验的报错信息,或者是想要校验在ModelForm中没有包含的field时才需要来自己调用full_clean()
这个方法。
Model.full_clean说明
Model.full_clean(exclude=None, validate_unique=True)
在Model.full_clean()
内部其实是会通过3个方法来进行不同层次的校验,对于这3个方法在后面会讲到。
参数:
可选参数exclude可以用来指定不需要执行校验的field。ModelForm也利用这个参数来将field排除。
参数validate_unique用来指定是否需要执行Model.validate_unique()
。
如何检查校验结果:
full_clean将会按序执行3个方法,这3个方法如果校验失败的话,会将相关信息写到异常的message_dict属性中,并且抛出ValidationError异常。
save()执行的时候是不会自动调用full_clean()来进行校验的。
手动校验model的合法性:
from django.core.exceptions import ValidationError
try:
article.full_clean()
except ValidationError as e:
# Do something based on the errors contained in e.message_dict.
# Display them to a user, or handle them programmatically.
pass
3个校验方法:
校验model fields –
Model.clean_fields()
校验整个model –
Model.clean()
校验field的唯一性 –
Model.validate_unique()
这几个步骤将会在调用model的full_clean()
方法时执行,流程如下:
st=>start: Model.full_clean
e=>end: return
io=>inputoutput: rais ValidationError
sub1=>subroutine: Model.clean_fields
cond1=>condition: valid
sub2=>subroutine: Model.clean
cond2=>condition: valid
sub3=>subroutine: Model.validate_unique
cond3=>condition: valid
st->sub1->cond1(yes)->sub2->cond2(yes)->sub3->cond3(yes)->e
st->sub1->cond1(no)->io
st->sub1->cond1(yes)->sub2->cond2(no)->io
st->sub1->cond1(yes)->sub2->cond2(yes)->sub3->cond3(no)->io
Model.clean_fields
Model.clean_fields(exclude=None)
这个方法将会校验排除exclude中指定的,model中的所有field。当它校验失败的时候,会抛出ValidationError异常。
Model.clean
如果你想要自定义model的校验,或者想要修改model的属性的话,就override这个方法。例如,你可以使用它来为field自动提供一个值:
import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == 'draft' and self.pub_date is not None:
raise ValidationError(_('Draft entries may not have a publication date.'))
# Set the pub_date for published items if it hasn't been set already.
if self.status == 'published' and self.pub_date is None:
self.pub_date = datetime.date.today()
当调用model的save()方法的时候,是不会调用Model.clean来进行校验的
校验中的错误处理
在上面的例子中,我们使用了ValidationError
来在Model.clean中抛出错误,这个错误信息将会存储在以NON_FIELD_ERRORS为key的字典中。这个key是用来存储对于整个model中的错误信息的。
如何获取校验的错误信息:
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
try:
article.full_clean()
except ValidationError as e:
non_field_errors = e.message_dict[NON_FIELD_ERRORS]
如何指定对于某个特定的field的校验错误信息:
class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == 'draft' and self.pub_date is not None:
raise ValidationError({'pub_date': _('Draft entries may not have a publication date.')})
...
如何指定多个field的校验错误信息:
raise ValidationError({
'title': ValidationError(_('Missing title.'), code='required'),
'pub_date': ValidationError(_('Invalid date.'), code='invalid'),
})
Model.validate_unique说明
Model.validate_unique(exclude=None)
最后,full_clean()将会检查model中的unique的限制。它在校验失败的时候会抛出ValidationError异常。
注意
值得注意的是:上面多次提到,在执行save()
方法的时候,是不会进行数据校验的。校验应该在save()
执行之前完成,你可以先在form进行校验,也可以在model中进行校验。但是,你必须确保通过这两个校验之后的数据是绝对没有问题的“干净”数据,然后再调用save()
方法将数据存储入库。