Default ordering using annotated fields

Hello! I am building an app with an admin panel and I needed to provide default sorting using annotated field. Was surprised, when it didn’t worked. Did a quick search and as I see it, this fails because my '.ordering’ or ‘get_ordering’ is called 2 times, and the first call happens from ‘BaseModelAdmin.get_queryset’, and as it is called before annotation is applied, it fails. Here is the code:
Here is my get queryset and ordering:

def get_queryset(self, request):
    qs = super().get_queryset(request).order_by()
    qs = annotate(
        _address=Coalesce("address_cleaned", "address_full")
    )
    return qs

def get_ordering(self, request):
    return ('_address',)

Here is get_queryset of BaseModelAdmin (I am using Django 5.2, but I looked and 6.0 has same code for this method):

def get_queryset(self, request):
    """
    Return a QuerySet of all model instances that can be edited by the
    admin site. This is used by changelist_view.
    """
    qs = self.model._default_manager.get_queryset()
    # TODO: this should be handled by some parameter to the ChangeList.
    ordering = self.get_ordering(request)
    if ordering:
        qs = qs.order_by(*ordering)
    return qs

This TODO hints that maybe this is a bug? As ordering IS set later in ChangeList, and it happens after queryset is annotated. So I decided to write here, maybe someone dealt already with default ordering in Admin using annotated fields? May this be considered a bug or feature request and should I create a ticket for it maybe, or if there is a TODO it’s already being handled?

Hello there, I believe that the ordering field is a quick way to order a queryset, so you don’t need to override get_queryset. But since you’re overriding get_queryset, why don’t you add the ordering right away?

def get_queryset(self, request):
    return (
        super()
        .get_queryset(request)
        .order_by()
        .annotate(_address=Coalesce("address_cleaned", "address_full"))
        .order_by("_address")
    )
1 Like

I thought about it as an alternative, but it doesn’t work if you have ordering defined on the model inside ‘Meta’, because it will be applied as well. And when ordering applied from ‘ordering’ or ‘get_ordering’ on ModelAdmin, it is not used, as I understand.