samix73
samix73

Reputation: 3063

Django: show the count of related objects in admin list_display

I would like to show the count of related objects in django's list_display property. for example we have a category field and we want to show how many blog posts are posted in this category

I have tried this so far:

admin.py:

from .models import Category

class CategoryAdmin(admin.ModelAdmin):
    def category_post_count(self, obj):
        return obj.post_set.count
category_post_count.short_description = "Posts Count"

list_display = ['category', 'category_post_count']

models.py:

class Category(models.Model):
    category = models.CharField(max_length=25)

class Post(models.Model):
    category = models.ForeignKey(Category, null=True, blank=False)

Upvotes: 23

Views: 13228

Answers (2)

Romain
Romain

Reputation: 821

Although the accepted answer will produce the expected result, this is not how it should be done in most cases because it will generate a "n+1" problem, a.k.a one more sql query per row.

You should modify your admin class (or manager if you need it in more situations than just the admin) to retrieve a count annotation (which is django's term for aggregate columns) and then use this value. It will compute the count in the main select query, avoiding generation of non necessary queries.

...
from django.db.models import Count
...

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = [..., 'post_count']

    ...

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

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        queryset = queryset.annotate(post_count=Count("post"))
        return queryset

Upvotes: 35

Ozgur Vatansever
Ozgur Vatansever

Reputation: 52183

.count is a function so you have to call it by appending parentheses () at the end:

def category_post_count(self, obj):
    return obj.post_set.count()

Upvotes: 18

Related Questions