具有索引、约束和权限的 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]
这是因为 A
在 Method 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?
我正在使用 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]
这是因为 A
在 Method 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 theMeta
, 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?