Django 1.8:如何确保模型中的两个字段,至少一个或只有一个必须满足条件?

Posted

技术标签:

【中文标题】Django 1.8:如何确保模型中的两个字段,至少一个或只有一个必须满足条件?【英文标题】:Django 1.8: How can I ensure that of Two Fields in a Model, At Least One or Only One must meet a condition? 【发布时间】:2015-10-25 09:45:52 【问题描述】:

对于上下文,这里是一个菜单系统。

class Menu(models.Model):
    ...


class Link(models.Model):
    ...


class MenuItem(models.Model):
    menu = models.ForeignKey(Menu)
    submenu = models.ForeignKey(Menu, related_name='submenu', blank=True, null=True)
    link = models.ForeignKey(Link, blank=True, null=True)
    position = models.IntegerField()

我希望达到两个结果:

子菜单和链接中至少有一个不得为空(子菜单标题可以有链接) 子菜单和链接中只有一个必须为空(子菜单标题不能有链接)

任何高级验证对我来说都是新的,所以一个代码示例会很有帮助。

在这个例子中,数据只会通过 Django Admin 来添加

【问题讨论】:

我没试过这个,所以我不会回答,但也许你可以使用多表继承?如果您同时创建MenuLink 子类MenuItem,那么MenuItem 将有两个一对一的关系,其中只有一个是非空的。 谢谢,这听起来可能是获得第二个结果的更简洁的方法,但不会涵盖第一个。 【参考方案1】:

关于模型验证的文档很差。有许多(已关闭)问题提到它,但仍不清楚。

此解决方案有效,无需更改任何表单:

from django.core.exceptions import ValidationError

class MenuItem(models.Model):
    ...

    def clean(self):
        super(MenuItem, self).clean()
        if self.submenu is None and self.link is None:
            raise ValidationError('Validation error text')

clean() 具有一些默认的验证功能,因此需要先调用属于 Model 的 clean。

以上确保至少使用了两个字段中的一个,如果不使用则引发异常。我只在管理界面中对此进行了测试。

我不知道这是否是正确的方法,如果有人对 Django 中的模型验证有更好的理解,我很想知道更多。来自其他语言和框架,这确实是编写自定义验证的自然方式。

【讨论】:

如果这些字段之一是多对多字段,如何做同样的检查?

以上是关于Django 1.8:如何确保模型中的两个字段,至少一个或只有一个必须满足条件?的主要内容,如果未能解决你的问题,请参考以下文章

确保字段对于 Django 模型中的另一个字段是唯一的

在 Django 中,我如何根据两个模型中的字段自动创建多对多条目

以原子方式比较-交换 Django 中的模型字段

Django Admin:如何在 oneToOne 关系中的两个模型中显示带有 list_display 的字段值?

Django模型中的下拉列表

如何强制 Django 模型中的 2 个字段共享相同的默认值?