具有索引、约束和权限的 Django 抽象模型:子 类 不继承属性

Django abstract model with indices, constraints and permissions: attributes are not inherited by sub classes

我正在使用 Django 3.2

我有以下型号:

app1

class IsPinnable(models.Model):
    is_pinned = models.BooleanField(default=False)
    pin_after_expiry_day_count = models.DurationField(default=0)    

    class Meta:
        abstract = True
        indexes = [
            models.Index(fields=['is_pinned' ]),
        ]
    


class IsModeratable(models.Model):
    approved = models.BooleanField(default=False)
    target_count_trigger = models.PositiveSmallIntegerField()
    positive_pass_count = models.PositiveSmallIntegerField(default=0)
    negative_pass_count = models.PositiveSmallIntegerField(default=0)
 
    # Other fields and methods ...

    def save(self, *args, **kwargs):
        # TODO: Sanity check on pass_count and trigger sizes
        # ...
        super().save(*args, **kwargs)


    class Meta:
        abstract = True
        permissions = (
                       ("moderate_item", "can moderate item"),
                       ("reset_moderation", "can (re)moderate a moderated item"),
                      )
        indexes = [
            models.Index(fields=['approved' ]),
        ]    

    class MyComponent(IsPinnable, IsModeratable):
        # some fields and methods ...

        class Meta(IsPinnable.Meta, IsModeratable.Meta):
            abstract = True
            
            # other stuff ...

app2

from app1.models import MyComponent

class Foo(MyComponent):
    # some fields and methods ...
    class Meta(MyComponent.Meta):
        abstract = False
   

现在,我知道抽象模型 classes 没有在数据库中创建 - 所以我最初期望 Django 在我尝试 makemigrations 时抛出异常 - 令我惊讶的是,我能够 makemigrations && migrate.

然而,当我检查数据库(通过 psql)时,我发现尽管 table app2_foo 具有其父 class 中描述的所有字段,但索引并未被正如 the documentation 所暗示的那样,从父 classes 继承而来。

我错过了什么?如何获取父 classes 中定义的索引、约束和权限以传播到子 classes?

这只是正常的 class 继承行为,以这个片段为例:

class A:
    attr = [1]


class B:
    attr = [2]


class C(A, B):
    pass


print(C.attr) # Outputs: [1]

这是因为 AMethod Resolution Order 中的 B 之前。如果假设 C 定义了 attr = [3] 那么输出将是 [3].

如果您需要覆盖这些属性,您可以在子 class 中执行类似的操作:

class MyComponent(IsPinnable, IsModeratable):
    # some fields and methods ...
    
    class Meta(IsPinnable.Meta, IsModeratable.Meta):
        abstract = True
        indexes = [...] + IsPinnable.Meta.indexes + IsModeratable.Meta.indexes # explicitly assign the indexes here

Note: Although What you want can be made possible if Django decides to put that logic in the meta class (this is different from Meta here) of the Meta, but I believe that would then require much work on their end to merge such attributes and would be backwards incompatible and honestly would be a weird feature, what if one doesn't want those indexes?