Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: show the count of related objects in admin list_display

Tags:

python

django

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)
like image 295
samix73 Avatar asked Sep 07 '15 17:09

samix73


People also ask

What does Django admin Startproject do?

at the end of the django-admin startproject command: (env) $ django-admin startproject <projectname> . The dot skips the top-level project folder and creates your management app and the manage.py file right inside your current working directory. You might encounter this syntax in some online Django tutorials.

What is List_filter in Django?

For Django 1.4-1.7, list_filter allows you to use a subclass of SimpleListFilter . It should be possible to create a simple list filter that lists the values you want.


2 Answers

.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()
like image 112
Ozgur Vatansever Avatar answered Sep 27 '22 20:09

Ozgur Vatansever


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

like image 41
Romain Avatar answered Sep 27 '22 21:09

Romain