views:

103

answers:

3

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?

A: 

Try something like this:

class PublisherAdminWithCount(Admin):

    def book_count(self, obj):
        return obj.book_set.count()

    list_display = ('user_count',)

admin.site.register(Group, PublisherAdminWithCount)
gruszczy
That column won't be sortable, unfortunately.
Daniel Roseman
+3  A: 

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',)
Andre Bossard
Oooh - that is pretty neat trick, but bear in mind that it'll add an annotation to everything you look up using that extended objects manager. If that's a problem, you could always create a second, standard manager without the aggregate and attach that as 'standard_objects', too. But that does increase complexity, obv
stevejalim
@stevejalim, that's right. If the counter doesn't have to be "live", you could also have a book_count Field on the publisher and updated it with a signal, whenever a book is saved.....
Andre Bossard
@Andre, when I try this I'm getting an error: "ordering" refers to "pubcount", a field that doesn't exist.
Gj
@Andre, also, how do you integrate this as a sortable column in the admin?
Gj
+1  A: 

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

Inshim
Thanks! works great
Gj