2014-02-21 56 views
4

對於我的一個模型,我需要確保某些行的unicity,但只在某些情況下。只有「已驗證」的行應該遵循這個約束。唯一在一起的約束,包括特定的字段值

基本上,我期待着像

class MyModel(models.Model): 
    field_a = models.CharField() 
    field_b = models.CharField() 
    validated = models.BooleanField(default=False) 

    class Meta: 
     unique_together = (('field_a', 'field_b', 'validated=True'),) 
+3

使用'unique_together'通過發出'UNIQUE'語句不是在django級別在db級別強制執行;它看起來不像(至少mysql)支持條件唯一。你可以在應用程序級別實現你想要的行爲 – dm03514

回答

7

你不能做到這一點與在Django unique_together,大概是因爲不是所有的數據庫後端將能夠支持它。

你可以做到這一點與模型驗證,而不是應用層:
https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects

class MyModel(models.Model): 
    field_a = models.CharField() 
    field_b = models.CharField() 
    validated = models.BooleanField(default=False) 

    def clean(self): 
     if not self.validated: 
      return 
     existing = self.__class__.objects.filter(field_a=self.field_a, 
               field_b=self.field_b).count() 
     if existing > 0: 
      raise ValidationError(
       "field_a and field_b must be unique if validated=True" 
      ) 

請注意,你可能會手動調用模型驗證,即

instance.clean() 
instance.save() 

保存模型時不會自動完成。在另一方面,它使用的ModelForm時自動完成,即

if form.is_valid(): 
    instance = form.save() 
1

除了前面的回答,您可以使用遞歸。這將是這樣的:

def save(self, **kwargs): 
    try: 
     self.objects.get(field_a=self.field_a, field_b=self.field_b, validated=True) 

     # this wont run if the previous line throw an exception 
     raise ValidationError(
      "field_a and field_b must be unique if validated=True" 
     ) 

    except self.__class__.DoesNotExist: # does not catch the ValidationError 
     super(MyModel, self).save(**kwargs) # everything cool 

現在你不需要調用clean()方法。