How to order a calculated count field in Django's admin

You can easily add a field which count a specific related model from a reverse ForeignKey relation or a ManyToMany relation, but ordering this field could not be easy from the first time.

Here we will see how to use annotate to add this field and how to order it. You only have to define admin_order_field as in the following.

A basic models example models.py:


    class Teacher(models.Model):
        name = models.CharField(max_length=255)

    class Student(models.Model):
        name = models.CharField(max_length=255)
        teacher = models.ForeignKey(Teacher)

And the admin.py


    @admin.register(Teacher)
    class TeacherAdmin(admin.ModelAdmin):
        list_display = (
            'id',
            'students_count',
        )

        def get_queryset(self, request):
            return Teacher.objects.annotate(students_count=Count('student'))

        def students_count(self, obj):
            return obj.students_count

        students_count.short_description = _('Students count')
        students_count.admin_order_field = 'students_count'

UPDATE (20/10/2022): With Django >= 3.2 you can use the new display decorator

    @admin.register(Teacher)
    class TeacherAdmin(admin.ModelAdmin):
        list_display = (
            'id',
            'students_count',
        )

        def get_queryset(self, request):
            return Teacher.objects.annotate(students_count=Count('student'))

        @admin.display(
            ordering='students_count',
            description=_('Students count'),
        )
        def students_count(self, obj):
            return obj.students_count