Mar 18, 2020 · Updated: Jul 12, 2021 · by Tim Kamanin
Here's a real-life case.
On this blog, I have two models:
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
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 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_fieldsupports query lookups like
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: