Django的資料驗證(validating objects)

weixin_33961829發表於2016-09-13

在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個校驗方法:

  1. 校驗model fields - Model.clean_fields()

  2. 校驗整個model - Model.clean()

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

相關文章