Django - Unexpected behaviour with default ordering after annotations

I've discovered a rather odd case where if I set default ordering on a model to id or -id then add distinct annotations to the query, the default ordering is ignored and instead orders by id ascending regardless of what it is set as in the model Meta.

However, when I choose a field that isn't specifically id as the default ordering of the model and do the same thing, the queryset is ordered correctly. It only seems to by id.

What gives? I'm not sure if this is Django weirdness or postgres weirdness, is it because it's the primary key? If I use .order_by('-id') afterwards it orders as desired and if the ordering gets broken by annotating it, how come it doesn't always break?

Example

Django version: 4.1 Postgres version: 13.4

class OrderQuerySet(models.QuerySet):
    def annotateItemCounts(self):
        return self.annotate(
            num_items=Count('order_items', distinct=True),
            num_items_draft=Count('order_items', distinct=True, filter=Q(order_items__state=OrderItem.OrderItemState.DRAFT)),
            num_items_back_order=Count('order_items', distinct=True, filter=Q(order_items__state=OrderItem.OrderItemState.BACK_ORDER)),
            num_items_confirmed=Count('order_items', distinct=True, filter=Q(order_items__state=OrderItem.OrderItemState.CONFIRMED)),
            num_items_in_progress=Count('order_items', distinct=True, filter=Q(order_items__state=OrderItem.OrderItemState.IN_PROGRESS)),
            num_items_ready=Count('order_items', distinct=True, filter=Q(order_items__state=OrderItem.OrderItemState.READY)),
            num_items_packed=Count('order_items', distinct=True, filter=Q(order_items__state=OrderItem.OrderItemState.PACKED)),
            num_items_shipped=Count('order_items', distinct=True, filter=Q(order_items__state=OrderItem.OrderItemState.SHIPPED)),
            num_items_completed=Count('order_items', distinct=True, filter=Q(order_items__state=OrderItem.OrderItemState.COMPLETE)),
        )


class OrderManager(models.Manager):
    def get_queryset(self):
        return OrderQuerySet(self.model, using=self._db)

    def annotateItemCounts(self):
        return self.get_queryset().annotateItemCounts()


class Order(models.Model):
    class Meta:
        ordering = ['-id']
...
Back to Top