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

rob*_*rob 5 django

我发现了一些与我的问题相似的问题,但其中大多数都过时了,或者太(或太少)冗长而无济于事。

我有一个这样的模型:

class Breakfast(models.Model):
    count_eggs = models.IntegerField()
    count_bacon = models.IntegerField()
    had_toast = models.BooleanField()
Run Code Online (Sandbox Code Playgroud)

现在,在构建 RESTful API 时,我需要能够按总数对早餐对象进行排序,count_eggs + count_bacon而无需将其永久存储在模型中。

许多当前和流行的问题都暗示了这样的事情:

Breakfast.objects.extra(
    select={'total_food':'count_eggs + count_bacon'},
    order_by=('total_food',)
)
Run Code Online (Sandbox Code Playgroud)

这似乎对许多人有效,但Django 文档似乎劝阻此解决方案。因此,在 1.10+ 世界中,对 Django 中的两个(或多个)字段的总和进行此类过滤的最佳/正确方法是什么?

Lat*_*ova 5

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

from django.db.models import F, Sum

Breakfast.objects.all().\
            annotate(total_food=Sum(
                F('count_eggs ') + F('count_bacon'))
            ).\
            order_by('total_food')
Run Code Online (Sandbox Code Playgroud)


oxa*_*org 5

Latrovas 的答案略有更正,尽管他的查询可以工作,但不需要 SUM 和 GROUP_BY。

更直观的查询如下:

Breakfast.objects.all().\
            annotate(total_food=F('count_eggs ') + F('count_bacon')
            ).order_by('total_food')
Run Code Online (Sandbox Code Playgroud)

我想更进一步向您解释查询在幕后如何工作:

当我们注释时,我们本质上是在SELECTSQL 语句中添加一列。因此,要执行两个字段的相加,我们需要一个像这样的 select 语句SELECT (eggs + bacon) as food

这正是幕后annotate所做的事情。

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

这正是表达式的作用F()

现在,您迟早会意识到,由于它们做了两种完全不同的事情,因此我们可以轻松地将两者结合起来,并将它们一起用于一些真正强大的东西!