首页 > 解决方案 > 如何告诉 Django 模型只有一个或其他字段不能为空?

问题描述

使用 Django models.Model 类:

class OrderLign(models.Model):
    Order = models.ForeignKey(Order,on_delete=models.CASCADE)
    Item = models.ForeignKey(Item, on_delete=models.RESTRICT, blank=True, default=0, null=True)
    Pack = models.ForeignKey(Pack,on_delete=models.RESTRICT, blank=True, default=0,
                             null=True)

我需要只有在设置了 Item OR Pack 时才可以保存 OrderLign,而不是两者都设置,也不是两者都设置。

标签: python-3.xdjangodjango-models

解决方案


您可以添加覆盖clean()方法 [Django-doc]来检查这一点。

此外,我们可以使用Django 的约束 API添加数据库约束并使用CheckConstraint[Django-doc]。如果数据库支持这一点,它将拒绝两个ForeignKeys 都没有的条目,或者如果两者都是 no None

from django.core.exceptions import ValidationError
from django.db.models import Q

class OrderLign(models.Model):
    order = models.ForeignKey(
        Order,
        on_delete=models.CASCADE
    )
    item = models.ForeignKey(
        Item,
        on_delete=models.RESTRICT,
        blank=True,
        null=True
    )
    pack = models.ForeignKey(
        Pack,
        on_delete=models.RESTRICT,
        blank=True,
        null=True
    )

    def clean(self, *args, **kwargs):
        if (self.item is None) == (self.pack is None):
            raise ValidationError('item or pack should be filled in')
        return super().clean(*args, **kwargs)

    class Meta:
        constraints = [
            models.CheckConstraint(
                check=Q(item=None, pack__isnull=False) |
                      Q(pack=None, item__isnull=False),
                name='one of the two not null'
            )
        ]

推荐阅读