Django 2 个字段之一不能为空
Posted
技术标签:
【中文标题】Django 2 个字段之一不能为空【英文标题】:Django one of 2 fields must not be null 【发布时间】:2019-04-04 18:06:37 【问题描述】:我有一个类似的模型:
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)
field1
或 field2
至少有一个字段不能为空。如何在模型中验证它?
【问题讨论】:
【参考方案1】:你可以使用Model.clean()
方法:
def clean(self):
if self.field1 is None and self.field2 is None:
raise ValidationError(_('field1 or field2 should not be null'))
见https://docs.djangoproject.com/en/2.1/ref/models/instances/#django.db.models.Model.clean
【讨论】:
【参考方案2】: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')
请注意,当您.save()
模型时,默认情况下不验证此 clean 方法。它通常仅由构建在此模型之上的ModelForm
s 调用。当您 .save()
模型实例时,您可以修补 .save()
方法 for example like here 以强制验证,但仍有一些方法可以通过 ORM规避。
django-db-constraints
(部分数据库不支持)
如果您的数据库支持它(例如 mysql simply ignores the CHECK
constraints),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)',
更新:Django 约束框架
由于django-2.2,您可以使用Django constraint framework [Django-doc]。使用此框架,您可以指定数据库约束,如果数据库支持这一点,则在数据库端进行验证。因此,您可以检查两个字段中的至少一个是否不是NULL
和CheckConstraint
[Django-doc]:
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:
constraints = [
models.CheckConstraint(
check=Q(field1__isnull=False) | Q(field2__isnull=False),
name='not_both_null'
)
]
【讨论】:
如果要定义两者之一(field1 或 field2),我们该怎么办。两者都不能为空,也不能定义。这类似于异或(XOR),但models.Q
似乎不支持这一点。
@ShubhamDhingra:你可以把它转换成析取范式,所以Q(field1__isnull=False, field2=None) | Q(field1=None, field2__isnull=False)
【参考方案3】:
从 Django 2.2 开始,您可以在 Django 中使用built-in constraints 功能。无需 3rd 方代码。
【讨论】:
以上是关于Django 2 个字段之一不能为空的主要内容,如果未能解决你的问题,请参考以下文章