I am using Django 3.2
I have the following models:
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 ...
from app1.models import MyComponent
class Foo(MyComponent):
# some fields and methods ...
class Meta(MyComponent.Meta):
abstract = False
Now, I know that abstract model classes are not created in the database - so I was initially expecting Django to throw an exception when I attempted to makemigrations
- to my surprise, I was able to makemigrations
&& migrate
.
However, when I inspected the database (via psql), I found that although table app2_foo
had all the fields described in it's parent class, the indixes were not being carried up from the parent classes as the the documentation would seem to suggest.
What am I missing?, and how do I get the indices, constrains and permissions defined in parent classes to propagate to sub classes?
This is just normal class inheritance behaviour, take this snippet for instance:
class A:
attr = [1]
class B:
attr = [2]
class C(A, B):
pass
print(C.attr) # Outputs: [1]
This is because A
is before B
in the Method Resolution Order. If suppose C
defined attr = [3]
then the output would have been [3]
.
You can do something like this in the child class if you need to override those attributes:
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?