0

The model Station has a FK to System. I want to display Station count as a column in the System admin change list. I have achieved this with the code below but I am having difficulty making the 'num_stations' column sortable.

model.py:

class System(models.Model):
    pass

class Station(models.Model):
   system_info = models.ForeignKey(System)

admin.py:

class SystemAdmin(admin.ModelAdmin):
    def num_stations(self, obj):
        return obj.station_set.count()

    # num_stations.admin_order_field = ????
    num_stations.short_description = 'stations'

    list_display = (num_stations',)

The ordinary 'station_set' syntax for a reverse relationship doesn't seem to work in the admin_order_field, even though other stack overflow question commonly show traversing a relation in the forward direction is supported e.g.

Greg Brown
  • 1,251
  • 1
  • 15
  • 32
  • 2
    The [question](https://stackoverflow.com/questions/2168475/django-admin-how-to-sort-by-one-of-the-custom-list-display-fields-that-has-no-d) that you linked to contains the answer. You need to override the queryset and annotate the count. It isn't possible to use `admin_order_field` to reference `station_set.count()`, and even if it was, it would be less efficient to do a count for every item in the queryset instead of the annotation. – Alasdair Apr 07 '17 at 13:01

1 Answers1

2

Thanks to Alasdair for their comment, the answer was in this question as pointed out. Here is the solution that fits my problem:

class SystemAdmin(admin.ModelAdmin):
    def num_stations(self, obj):
        return obj.num_stations

    def get_queryset(self, request):
        # def queryset(self, request): # For Django <1.6
        qs = super(SystemAdmin, self).get_queryset(request)
        # qs = super(CustomerAdmin, self).queryset(request) # For Django <1.6
        qs = qs.annotate(num_stations=Count('station'))
        return qs

    num_stations.admin_order_field = 'num_stations'
    num_stations.short_description = 'stations'

    list_display = ('num_stations', )
Greg Brown
  • 1,251
  • 1
  • 15
  • 32