Django 2个字段之一不能为null

use*_*014 5 python django python-3.x

我有一个与此模型类似的模型:

class Person(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    field1= models.IntegerField(null=True)
    field2 = models.IntegerField(null=True)
Run Code Online (Sandbox Code Playgroud)

至少一个字段,field1或者field2不能为null。如何在模型中验证?

Wil*_*sem 7

Model.clean

通常在Model.clean[Django-doc]中编写这样的测试:

from django.core.exceptions import ValidationError

class Person(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    field1= models.IntegerField(null=True)
    field2 = models.IntegerField(null=True)

    def clean(self):
        super().clean()
        if self.field1 is None and self.field2 is None:
            raise ValidationError('Field1 or field2 are both None')
Run Code Online (Sandbox Code Playgroud)

请注意,在您建模时,默认情况下不会验证此干净方法.save()。通常仅由ModelForm基于此模型的s 调用。例如,您可以在此处修补.save()方法,例如.save()在模型实例时强制执行验证,但是仍然存在通过ORM 规避此方法的方法。

django-db-constraints (某些数据库不支持)

如果您的数据库支持它(例如MySQL仅忽略CHECK约束),则SQL提供一种添加额外约束的语法,而Django包django-db-constraints[GitHub]提供一些工具来指定此类约束,例如:

class Person(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    field1= models.IntegerField(null=True)
    field2 = models.IntegerField(null=True)

    class Meta:
        db_constraints = {
            'field_null': 'CHECK (field1 IS NOT NULL OR field2 IS NOT NULL)',
        }
Run Code Online (Sandbox Code Playgroud)

  • @ShubhamDhingra:您可以将其转换为析取范式,因此 `Q(field1__isnull=False, field2=None) | Q(field1=None, field2__isnull=False)` (8认同)
  • 如果要定义两者之一(field1 或 field2),我们该怎么办?两者都不能为 null,也不能同时被定义。这就像异或(XOR),但“models.Q”似乎不支持这一点。 (2认同)

Sat*_*evg 5

您可以使用Model.clean()方法:

def clean(self):
    if self.field1 is None and self.field2 is None:
        raise ValidationError(_('field1 or field2 should not be null'))
Run Code Online (Sandbox Code Playgroud)

请参阅https://docs.djangoproject.com/en/2.1/ref/models/instances/#django.db.models.Model.clean