Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Admin, sort with custom function

How can I sort a column in Django admin by some simple custom method?
(All the answers I got through was by using annotate but I don't know how to use it my case).

Assume the model

class Shots(models.Model):    
    hits = models.PositiveIntegerField()
    all = models.PositiveIntegerField()

In admin site I would like to sort by hits to all ratio:

class ShotAdmin(admin.ModelAdmin):
    list_display = ['ratio']

    def ratio(self, obj):
        return obj.hits / obj.all * 100

I know the ratio is not a field in DB thus simple ratio.admin_order_field = 'ratio' won't work and I need to somehow append this as a field but I have no idea how.

like image 255
micsza Avatar asked Aug 28 '17 14:08

micsza


People also ask

How to set ordering of apps and models in Django admin dashboard?

How to set ordering of Apps and models in Django admin dashboard. ¶ Django, by default, orders the models in admin alphabetically. So the order of models in Event admin is Epic, EventHero, EventVillain, Event Instead you want the order to be EventHero, EventVillain, Epic then event.

How to sort list_display by first_name in Django?

However, if an element of list_display represents a certain database field, you can indicate this fact by using the display () decorator on the method, passing the ordering argument: The above will tell Django to order by the first_name field when trying to sort by colored_first_name in the admin.

What is Django admin customization?

Watch it together with the written tutorial to deepen your understanding: Django Admin Customization The Django framework comes with a powerful administrative tool called admin. You can use it out of the box to quickly add, delete, or edit any database model from a web interface.

How do I set the default order of objects in Django?

Adding the ordering attribute will default all queries on Person to be ordered by last_name then first_name. Django will respect this default order both in the admin and when fetching objects. The list_display tuple can reference any attribute of the object being listed.


1 Answers

By following:

  • The accepted answer to this post: Django admin: how to sort by one of the custom list_display fields that has no database field
  • The How to execute arithmetic operations between Model fields in django
    (Disclaimer: I have composed that Q&A style example)

We can compose a solution to your problem:

from django.db.models import F

class ShotsAdmin(admin.ModelAdmin):
    list_display = ('get_ratio',)

    def get_queryset(self, request):
        qs = super(ShotsAdmin, self).get_queryset(request)
        qs = qs.annotate(ratio=F('hits') * 100 / F('all'))
        return qs

    def get_ratio(self, obj):
        return obj.ratio

    get_ratio.admin_order_field = 'ratio'

Explanation:

  • The get_queryset method will annotate a new field named ratio to your queryset. That field's value is the application of your ratio function on the hits and all fields.
  • The get_ratio function returns the aforementioned field from a queryset instance.
  • Finally: get_ratio.admin_order_field = 'ratio' sets the ratio field as the ordering field for your queryset on the admin panel.
like image 62
John Moutafis Avatar answered Oct 07 '22 13:10

John Moutafis