2017-03-07 77 views
2

我有我的数据库表和模型下面的两个字段(型号名称订购):Django管理使分拣计算领域

id, branch_id, product_id, cost, quantity, status, ordered_at 

而且我在OrderModelAdmin下面的代码:

list_display = (
    'order_number', 
    'branch', 
    'product', 
    'cost', 
    'quantity', 
    'calculated_total', 
    'status', 
    'ordered_at', 
) 

def calculated_total(self, obj): 
    return obj.cost * obj.quantity 
calculated_total.short_description = _('Total') 

现在,我想启用该字段的排序。在现实中,我需要做的是在我的SELECT语句中添加一列:

SELECT (t.cost * t.quantity) as TOTAL 
ORDER BY TOTAL 

有没有一种方法,我可以追加SQL语句在Django管理排序?

回答

5

无法通过calculated_total方法的结果进行排序。

但是,您可以通过覆盖模型管理员的get_queryset方法和计算相同内容的ordering by an expression来设置模型管理员的默认排序。

class OrderModelAdmin(admin.ModelAdmin): 
    ... 
    def get_queryset(self, request): 
     qs = super(OrderModelAdmin, self).get_queryset(request) 
     qs = qs.order_by(F('cost')*F('quantity')) 
     return qs 

一个类似的方法是用总数对查询集进行注释,然后按该字段排序。假设成本为DecimalField,数量为IntegerField,则需要使用ExpressionWrapper来设置输出字段。有关更多信息,请参阅Using F() with annotations上的文档。

我不认为有可能直接在list_display中使用total。但是,您可以更改您的calculated_total方法以访问带注释的字段。我们设置了calculate_total.admin_order_field ='total',这样Django管理员可以通过点击它来对该列进行排序。

from django.db.models import F, ExpressionWrapper, DecimalField 

class OrderModelAdmin(admin.ModelAdmin): 
    list_display = ['name', 'number', 'price', 'calculated_total'] 

    def calculated_total(self, obj): 
     return obj.total 
    calculated_total.admin_order_field = 'total' 

    def get_queryset(self, request): 
     qs = super(OrderModelAdmin, self).get_queryset(request) 
     qs = qs.annotate(total=ExpressionWrapper(F('cost')*F('quantity'), output_field=DecimalField())).order_by('total') 
     return qs 
+0

我用注解,它工作正常,它是有道理的,但上面的代码需要一些调整。我不得不添加'calculated_total.admin_order_field ='total''。实际上,这正是我所期待的。能够添加自定义列并根据该列对该字段进行排序。谢谢! – Gasim

+0

@Gasim好点!默认情况下,我的原始答案按总数排序查询集。如果您想要点击列进行排序,您需要设置“admin_order_field”。我已经添加了答案。 – Alasdair