Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Admin: Order by value on related Foreign Key

I'm trying to sort a Django Admin list page by a specific value in the objects' related foreign key set.

Specifically, in the below code, I want the ContentAdmin view to show a list of all content objects sorted by the "Twitter Score" (The Score object with name "Twitter").

In the django app I have the following models:

class Content(models.Model):
    body = models.CharField(max_length=564)
    title = models.CharField(max_length=64) 

class Score(models.Model):
    name = models.CharField(max_length=64)
    score = models.IntegerField()
    content = models.ForeignKey('Content')

And in the admin.py I have the following:

class ContentAdmin(admin.ModelAdmin):
    list_display = ('title', 'show_twitter_score',)

    def show_twitter_score(self, obj):
        twitter_score = obj.score_set.get(name='Twitter')
        return 'Twitter: ' + str(twitter_score.score)

GOAL: The admin panel for ContentAdmin displays the content objects ordered by "Twitter" scores

Thanks everyone!

like image 353
djs22 Avatar asked Apr 19 '12 19:04

djs22


2 Answers

I solved this by extending the get_queryset method of the ContentAdmin class. After that, it was just a matter of getting the right ORM query

def get_queryset(self, request):
    qs = super(ContentAdmin, self).get_queryset(request)
    return qs.filter(score__name='Twitter').order_by('-score__score')

For Django 1.5 and earlier, the method was queryset.

def queryset(self, request):
    qs = super(ContentAdmin, self).queryset(request)
    return qs.filter(score__name='Twitter').order_by('-score__score')
like image 124
djs22 Avatar answered Sep 19 '22 03:09

djs22


If I understand correctly, you can try this from ModelAdmin.list_display in Django's documentation:

Usually, elements of list_display that aren't actual database fields can't be used in sorting (because Django does all the sorting at the database level).

However, if an element of list_display represents a certain database field, you can indicate this fact by setting the admin_order_field attribute of the item.

For example:

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    color_code = models.CharField(max_length=6)

    def colored_first_name(self):
        return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name)
    colored_first_name.allow_tags = True
    colored_first_name.admin_order_field = 'first_name'

class PersonAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'colored_first_name')

The above will tell Django to order by the first_name field when trying to sort by colored_first_name in the admin.

You can try this workaround in your code for the sorting.

like image 40
César Avatar answered Sep 21 '22 03:09

César