2011-09-09 58 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