在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()
方法將資料儲存入庫。