具有未继承约束的 Django 模型抽象模型:“约束”指的是字段“xxx”,它不是模型“Foo”的本地字段

Posted

技术标签:

【中文标题】具有未继承约束的 Django 模型抽象模型:“约束”指的是字段“xxx”,它不是模型“Foo”的本地字段【英文标题】:Django model abstract model with constrains not being inherited: 'constraints' refers to field 'xxx' which is not local to model 'Foo' 【发布时间】:2021-08-15 03:03:22 【问题描述】:

我正在使用 Django 3.2

我遇到了一个奇怪的行为,这似乎是一个错误;在 ABC 中定义的约束中使用的字段不会被子类继承。

myapp/models.py

class BaseFoo(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE,related_name='%(class)s_content_type')
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    user = models.ForeignKey(User, blank=False, null=False, on_delete=models.CASCADE,related_name='%(class)s')
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        abstract = True
        constraints = [
            models.UniqueConstraint(fields=['content_object', 'user'], name="'%(class)s_unique"),
        ]
    
class Foo(BaseFoo):
    class Meta(BaseFoo.Meta):
        abstract = False

当我makemigrations 时没有问题,但是,当我尝试迁移架构时(`python manage.py migrate),我收到以下错误:

myapp.Foo: (models.E016) 'constraints' 指的是字段 'content_object',它不是模型 'Foo' 的本地字段。 提示:这个问题可能是多表继承引起的。

为什么 Foo 没有继承父 ABC 中明确定义的字段? - 我该如何解决这个问题(假设它不是错误)?

【问题讨论】:

【参考方案1】:

1.您不能在UniqueConstraint 中使用GenericForeignKey,因为GenericForeignKey 不是普通的字段对象。而在UniqueConstraint 中使用content_typeobject_id,这相当于content_object


class Meta:
    abstract = True
    constraints = [
        models.UniqueConstraint(
            fields=['content_type', 'object_id', 'user'], 
            name="%(app_label)s_%(class)s_user_unique"),
    ]

见Django Docs:

由于GenericForeignKey的实现方式,不能使用 此类字段直接带有过滤器(filter()exclude(),例如 示例)通过数据库 API。因为GenericForeignKey 不是普通的字段对象。

同样,GenericForeignKey 不会出现在 ModelForms 中。

2.根据Django Docs抽象基类related_name必须包含'%(app_label)s'和'%(class)s'。并且您应该始终为该字段指定一个唯一的反向名称和查询名称。

content_type = models.ForeignKey(
   ContentType, on_delete=models.CASCADE,
   related_name='%(app_label)s_%(class)s_content_types',
   related_query_name='%(app_label)s_%(class)s_content_type',
)

user = models.ForeignKey(
    User, blank=False, null=False,
    on_delete=models.CASCADE,
    related_name='%(app_label)s_%(class)s_users',
    related_query_name='%(app_label)s_%(class)s_user',
)

如果您使用 related_namerelated_query_name ForeignKeyManyToManyField,您必须始终为字段指定唯一的反向名称和查询名称。这通常会 在抽象基类中引起问题,因为此字段 类被包含在每个子类中,确切地说是 属性的相同值(包括 related_namerelated_query_name)每次。

要解决此问题,当您使用 related_namerelated_query_name 在抽象基类中(仅),部分值 应包含“%(app_label)s”和“%(class)s”。

【讨论】:

感谢您的回答 - 但您自己尝试过吗?它对错误没有影响。在对代码进行建议的更改后,我仍然遇到相同的错误。 @HomunculusReticulli,刚刚测试过。错误来自您的UniqueConstraintcontent_object 不是真正的专栏。请改用:models.UniqueConstraint(fields=['content_type', 'object_id', 'user'], name="%(app_label)s_%(class)s_user_unique"),。我编辑了我的答案。

以上是关于具有未继承约束的 Django 模型抽象模型:“约束”指的是字段“xxx”,它不是模型“Foo”的本地字段的主要内容,如果未能解决你的问题,请参考以下文章

不能使用继承的 Django 模型的 Meta 类来配置在继承的抽象模型中定义的字段

django抽象模型继承导入

Django:从带有元的抽象类的多重继承

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

在 django 中获取继承的模型对象

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