diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 36b51e657..389ee4209 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,7 @@ Fixed - ``QuerySet.count()`` now matches the limited query result for the LIMIT/OFFSET edge cases: it returns ``0`` (instead of a negative number) when ``offset()`` exceeds the total row count, and ``0`` (instead of the total) for ``limit(0)``. (#2208) - Field declarations on models now resolve to their concrete type (e.g. ``CharField[str]``) in Pyright/Pylance instead of ``Field[Unknown]``; the ``Field.__new__`` type-check stub now returns ``Self``. (#2216) - ``TransactionContext`` now returns a ``TransactionalDBClient`` instead of a raw database connection. This change gives the correct inferred type for the transaction context. (#2232) +- A model with its own ``Meta`` now inherits ``Meta.ordering`` from its abstract base model when it does not define its own. (#2046) 1.1.7 diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py index 5224710d6..6ebea599c 100644 --- a/tests/test_inheritance.py +++ b/tests/test_inheritance.py @@ -15,3 +15,37 @@ async def test_basic(db): await model.save() assert model.created_at is not None assert model.modified_at is not None + + +def test_abstract_meta_ordering_is_inherited(): + """A subclass without its own ``Meta.ordering`` inherits the abstract + base's ordering, while a subclass that defines its own keeps it and an + explicitly empty ordering stays empty (#2046).""" + from tortoise import fields + from tortoise.models import Model + + class OrderedBase(Model): + value = fields.IntField() + + class Meta: + abstract = True + ordering = ["-value"] + + class InheritsOrdering(OrderedBase): + class Meta: + abstract = True + + class OwnOrdering(OrderedBase): + class Meta: + abstract = True + ordering = ["value"] + + class EmptyOrdering(OrderedBase): + class Meta: + abstract = True + ordering = [] + + assert OrderedBase._meta._default_ordering != () + assert InheritsOrdering._meta._default_ordering == OrderedBase._meta._default_ordering + assert OwnOrdering._meta._default_ordering != OrderedBase._meta._default_ordering + assert EmptyOrdering._meta._default_ordering == () diff --git a/tortoise/models.py b/tortoise/models.py index aa20fdbd6..e93b86eb7 100644 --- a/tortoise/models.py +++ b/tortoise/models.py @@ -539,6 +539,15 @@ def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> M pk_attr, ) + # Inherit the default ordering from an abstract base model when the + # subclass's own Meta does not define one (#2046). + if not hasattr(meta_class, "ordering"): + for base in bases: + base_meta = getattr(base, "_meta", None) + if base_meta is not None and base_meta._default_ordering: + meta._default_ordering = base_meta._default_ordering + break + new_class = super().__new__(cls, name, bases, attrs) for field in meta.fields_map.values(): field.model = new_class # type: ignore