【问题标题】:Django one of 2 fields must not be nullDjango 2 个字段之一不能为空
【发布时间】: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)

field1field2 至少有一个字段不能为空。如何在模型中验证它?

【问题讨论】:

    标签: python django python-3.x


    【解决方案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 方法。它通常仅由构建在此模型之上的ModelForms 调用。当您 .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 constraint framework [Django-doc]。使用此框架,您可以指定数据库约束,如果数据库支持这一点,则在数据库端进行验证。因此,您可以检查两个字段中的至少一个是否不是NULLCheckConstraint [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 方代码。

      【讨论】:

        猜你喜欢
        • 2020-06-24
        • 1970-01-01
        • 2018-11-22
        • 2015-05-06
        • 1970-01-01
        • 2022-08-20
        • 2020-01-22
        • 2019-09-05
        • 1970-01-01
        相关资源
        最近更新 更多