2011-09-09 234 views
28

我有一個開始和結束日期範圍的Django模型。我想執行驗證,以便沒有兩個記錄具有重疊的日期範圍。什麼是最簡單的方式來實現這一點,以便我不必重複自己寫這種邏輯?添加自定義Django模型驗證

例如我不想以表格 a ModelForm管理員表格重新實現此邏輯,該模型的覆蓋save()

據我所知,Django並不容易全球執行這些類型的標準。

谷歌搜索並沒有太大的幫助,因爲「模型驗證」通常是指驗證特定的模型字段,而不是整個模型內容或字段之間的關係。

回答

27

我發現有用的基本模式是把我所有的自定義驗證在clean(),然後簡單地調用full_clean()(它調用clean()和一些其他方法)從裏面save(),如:

class BaseModel(models.Model): 

    def clean(self, *args, **kwargs): 
     # add custom validation here 
     super(BaseModel, self).clean(*args, **kwargs) 

    def save(self, *args, **kwargs): 
     self.full_clean() 
     super(BaseModel, self).save(*args, **kwargs) 

這如here所解釋的,因爲它會干擾某些功能,但這些對我的應用程序來說不是問題。

8

我認爲你應該使用這樣的: https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects

就在你的模型是這樣定義清潔()方法:(例如,從文檔鏈接)

def clean(self): 
    from django.core.exceptions import ValidationError 
    # 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.datetime.now() 
+0

這就近了。我也必須重寫模型的save(),並從那裏調用clean()。 – Cerin

+1

但是什麼? AdminSite(ModelForm)自動調用clean()。但是從save()方法調用clean()可能會在意想不到的時刻產生ValidationError,並且不會像預期的那樣發生。 – alTus

+6

並非所有的東西都叫乾淨。無論保存的位置如何,都需要進行驗證。破損的網站頁面可能會損壞數據。 – Cerin

16

我將在覆蓋validate_unique方法該模型。爲了確保您忽略驗證時,當前的對象,你可以使用以下命令:

from django.db.models import Model, DateTimeField 
from django.core.validators import NON_FIELD_ERRORS, ValidationError 

class MyModel(Model): 
    start_date = DateTimeField() 
    end_date = DateTimeField() 

    def validate_unique(self, *args, **kwargs): 
     super(MyModel, self).validate_unique(*args, **kwargs) 

     qs = self.__class__._default_manager.filter(
      start_date__lt=self.end_date, 
      end_date__gt=self.start_date 
     ) 

     if not self._state.adding and self.pk is not None: 
      qs = qs.exclude(pk=self.pk) 

     if qs.exists(): 
      raise ValidationError({ 
       NON_FIELD_ERRORS: ['overlapping date range',], 
      }) 

ModelForm會自動通過full_clean(),您可以手動使用過調用此爲您服務。

PPR對簡單,正確的range overlap condition進行了很好的討論。

+0

在django 1.3.1上,我遇到了一個以你描述它的方式引發ValidationError的問題。我可以通過在引發異常時傳遞{field:(error_msg,)}字典而不是字符串error_msg來解決此問題。 – adam

+5

'從django.core.exceptions進口ValidationError,NON_FIELD_ERRORS' '提高ValidationError({NON_FIELD_ERRORS:( '重疊的日期範圍')})' – adam

+2

是否有延長'validate_unique',而不是僅僅定義'clean'任何權益?只是組織代碼的問題? – lajarre