使用继承类中的字段的 Django 模型约束条件 - 可能吗?

Posted

技术标签:

【中文标题】使用继承类中的字段的 Django 模型约束条件 - 可能吗?【英文标题】:Django Model Constraint Condition Using Field From Inherited Class - Is It Possible? 【发布时间】:2021-12-07 15:36:33 【问题描述】:

我想使用父类的字段作为子类的约束条件。

models.py

class ParentClass(object):
    ...
    is_public = models.BooleanField(default=False)


class ChildClass(ParentClass):
    ...
    price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
    class Meta:
        constraints = [
            models.CheckConstraint(
                check=Q(price__isnull=True) & Q(is_public=True), # <- here
                name='price_exists_check',
            )
        ]

当我尝试迁移时,我在终端中看到此错误:

myapp.ChildClass: (models.E016) 'constraints' refers to field 'is_public'
  which is not local to model 'ChildClass'.
  HINT: This issue may be caused by multi-table inheritance.

很明显为什么我会看到此错误(is_public 字段位于 ParentClass)。我的问题是,那是不可能的,还是我可以重构一些东西?

我的最终目标是什么?

如果pricenull,则不要让ChildClass is_pulic 的实例更改为True。我想在数据库级别执行此操作。

有没有办法,如果有,需要改变什么?

【问题讨论】:

将父类标记为抽象类有帮助吗?见***.com/a/36824386/530160 还是需要父类是具体类? 我确实需要父类是一个具体的类。 【参考方案1】:

我的问题是,那是不可能的,还是我可以重构一些东西?

我找到了original commit,它介绍了您看到的错误消息,以及它正在修复的bug。 model inheritance 上的文档也有助于理解这一点。

我是这样理解这个问题的:

如果您创建一个从另一个模型继承的 Django 模型,并且该模型不是抽象的,那么 Django 会为父表创建一个外键,而不是在子表中重复父模型中的所有字段。因此,当您创建 ChildClass 对象时,会在 ChildClass 表 ParentClass 表中创建一行。

您不能创建引用多个表的 CHECK 约束。 (据我所知。)因此,Django 禁止您创建此约束。

因此,您有以下选择:

    在 ORM 层强制执行。在 clean() 方法中,检查您的约束是否满足。 (Documentation.) 如果非 Django 程序修改数据库,这不会防止违反约束。

    使父类抽象。你已经说过这是行不通的。

    创建第三个类,它们都继承自。像这样创建一个基类:

                -------------
                | BaseClass |
                -------------
                |           |
                V           V
    ---------------       --------------
    | ParentClass |       | ChildClass |
    ---------------       --------------
    

    将 BaseClass 抽象化,将 ParentClass 和 ChildClass 具体化。这允许您使用约束,因为 ChildClass 数据现在只在一个表中。

【讨论】:

以上是关于使用继承类中的字段的 Django 模型约束条件 - 可能吗?的主要内容,如果未能解决你的问题,请参考以下文章

Django的模型层

约束 unique_together 可能与 django 类中的唯一字段冲突

Django-模型

Django:为可重用模型字段创建一个 Mixin

Python / Django中多个抽象模型继承中的字段菱形模式

Django模型类中,内部类 class Meta:的行为特征实用总结