Dmitry Fedotkin
Dmitry Fedotkin

Reputation: 272

Django admin: how to sort column by custom method

 class Item(models.Model):
     name = models.CharField(max_length=100, unique=True)

     def admin_amount(self):
         total = self.warehouse_set.all().aggregate(item=Sum('amount'))
         return total['item']

 class Warehouse(models.Model):
     name = models.CharField(max_length=100, unique=True)
     item = models.ForeignKey('Item', blank=True, null=True)
     amount = models.IntegerField()

Create new field is wrong, but I cant do something like:

 admin_amount.admin_order_field = 'admin_amount'

I found similar question but I encountered a problem with rewriting queryset() method(can't write something like qs.warehouse_set.all().annotate(models.Sum('amount'))). Is there any way to adapt this solution for me or in my case, there is another solution?

Upvotes: 16

Views: 10548

Answers (1)

mfitzp
mfitzp

Reputation: 15545

Using the code in the linked question (and the suggested edit), the bottom should do it for your example. The principle is to use annotate to add additional data from a sub-query to the returned QuerySet. In this case the Sum of the amounts in warehouses.

Next you add a wrapper function amount_in_warehouses to get this value out for each row, and tell the admin to show this for listing list_display = ('amount_in_warehouses',), and sort on it amount_in_warehouses.admin_order_field = 'amount_in_warehouses'.

class ItemAdmin(admin.ModelAdmin):
    list_display = ('amount_in_warehouses',)
    name = models.CharField(max_length=100, unique=True)

    def queryset(self, request):
        qs = super(ItemAdmin, self).queryset(request)
        qs = qs.annotate(models.Sum('warehouse__amount'))
        return qs

    def amount_in_warehouses(self, obj):
        return obj.warehouse__amount__sum
    amount_in_warehouses.admin_order_field = 'amount_in_warehouses'

Upvotes: 23

Related Questions