Mar 18, 2020 ยท Updated: Jul 12, 2021 ยท by Tim Kamanin
Here's a real-life case.
On this blog, I have two models: Post
and PostStats
. As you may have already guessed, the first is for posts and the second is for statistics on each post, such as the number of views.
Here is a simplified version of both models:
class Post(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
class PostStats(models.Model):
post = models.ForeignKey(
"Post", on_delete=models.CASCADE, related_name="post_stats"
)
view_count = models.PositiveIntegerField(default=0)
I have the following ModelAdmin class for the Post
model:
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "live"]
Now I want to add the 'view_count' column from the related PostStats
model to PostAdmin
and do sorting on that column.
My first intention was to declare view_count
as a query lookup:
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "live", "post_stats__view_count"]
Note, I added post_stats__view_count
where post_stats
is the name of the Post -> PostStats
relationship, and view_count
is the name of the field I want to sort by. Unfortunately, ModelAdmin
wasn't happy about it and threw me an error.
Then, let's try something else. So you can add a synthetic column to ModelAdmin
as follows:
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "live", "get_view_count"]
def get_view_count(self, obj):
return obj.tutorialstats.view_count
This gives us a get_view_count
column with the desired value, but there are still two issues: you can't click to sort the column, and its name is ugly.
After digging around in the innards of ModelAdmin
a bit, I finally found a solution! It turns out that get_view_count
method can have two properties (actually it can have more, but we are only interested in the following two):
admin_order_field
- is the name of the field by which you want to sort the custom column. The cool thing is that admin_order_field
supports query lookups like stats__view_count
, bingo!;short_description
- allows you to change the name of the column.Now we have everything we need to solve our problem, and the complete solution looks like this:
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "live", "get_view_count"]
def get_view_count(self, obj):
return obj.tutorialstats.view_count
get_view_count.admin_order_field = "post_stats__view_count"
get_view_count.short_description = "View count"
Click on the "View count " column, and you will get the results of the admin list, sorted by the value of the column.
Hey, if you've found this useful, please share the post to help other folks find it: