Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a sortable count column to the Django admin of a model with a many-to-one relation?

Suppose I have a Book model containing a foreign key to a Publisher model.

How can I display in the Django admin a column with the number of books published by each publisher, in a way that I can use the built-in sorting?

like image 365
GJ. Avatar asked Aug 16 '10 08:08

GJ.


People also ask

What is the Changelist in Django admin?

Django Admin's "change list" is the page that lists all objects of a given model. Now, all your articles should have a different name, and more explicit than "Article object".


3 Answers

I had the same issue (I cannot change my model's manager to add slow annotations or joins). A combination of two of the answers here works. @Andre is really close, the Django Admin supports modifying the queryset for just the admin, so apply the same logic here and then user the admin_order_field attribute. You still need to add the new admin field to list_display, of course.

from django.db.models import Count  class EventAdmin(admin.ModelAdmin)     list_display = (..., 'show_artist_count')      def queryset(self, request):     # def get_queryset(self, request):    for Django 1.6+         qs = super(EventAdmin, self).queryset(request)         return qs.annotate(artist_count=Count('artists'))      def show_artist_count(self, inst):         return inst.artist_count     show_artist_count.admin_order_field = 'artist_count' 
like image 89
Lincoln B Avatar answered Sep 23 '22 03:09

Lincoln B


Try this:

make a new Manager (and aggregate with count on the book relation field):

class PublisherManager(models.Manager):     def get_query_set(self):         return super(PublisherManager,self).get_query_set().annotate(pubcount=Count('book')) 

sort it on pubcount:

class Publisher(models.Model):     ......     objects = PublisherManager()      class Meta:         ordering = ('pubcount',) 
like image 28
Andre Bossard Avatar answered Sep 25 '22 03:09

Andre Bossard


You should indeed start off with adding:

class PublisherManager(models.Manager):
    def get_query_set(self):
        return super(PublisherManager,self).get_query_set().annotate(pubcount=Count('book'))

But the correct way to add it as a sortable field is:

class Publisher(models.Model):
    ......
    objects = PublisherManager()

    def count(self):
        return self.pubcount
    count.admin_order_field = 'pubcount'

And then you can just add 'count' to the list_display attribute of model admin in admin.py

like image 26
GJ. Avatar answered Sep 25 '22 03:09

GJ.