通过两个(或更多)字段的总和对django查询集进行排序

时间:2017-12-11 17:06:52

标签: django

我发现了一些类似于我的问题,但是大多数问题已经过时,或者过于(或太少)冗长而且有用。

我有一个这样的模型:

class Breakfast(models.Model):
    count_eggs = models.IntegerField()
    count_bacon = models.IntegerField()
    had_toast = models.BooleanField()

现在,在构建RESTful API时,我需要能够按count_eggs + count_bacon总计对Breakfast对象进行排序,而不会将其永久存储在模型上。

许多当前和流行的问题都表明这样的事情:

Breakfast.objects.extra(
    select={'total_food':'count_eggs + count_bacon'},
    order_by=('total_food',)
)

这似乎适用于许多人,但Django docs appear to dissuade this solution。那么,在1.10+世界中,对Django中两个(或更多)字段的总和进行此类过滤的最佳/正确方法是什么

2 个答案:

答案 0 :(得分:4)

你应该使用注释,我有一个我的例子并适应你的情况,试试这个:

from django.db.models import F, Sum

Breakfast.objects.all().\
            annotate(total_food=Sum(
                F('count_eggs ') + F('count_bacon'))
            ).\
            order_by('total_food')

答案 1 :(得分:2)

Latrovas的答案略有改动,虽然他的查询可行,但SUM和GROUP_BY是不必要的。

更直观的查询如下:

Breakfast.objects.all().\
            annotate(total_food=F('count_eggs ') + F('count_bacon')
            ).order_by('total_food')

我想更进一步,向您解释查询在幕后的工作原理:

当我们注释时,我们实际上是在SQL的SELECT语句中添加一列。因此,为了执行两个字段的添加,我们需要一个像SELECT (eggs + bacon) as food这样的选择语句。

完全 annotate在幕后所做的事情。

但是,我们需要使用存储在数据库中的项目,而不是使用硬编码值,即eggsbacon表达式等列名。

完全 F()表达式的作用。

现在这是一个时间问题,你才意识到,因为他们做了两件完全不同的事情,我们可以轻松地将两者结合起来,并将它们一起用于一些非常强大的东西!