与 django 查询集注释中的先前对象的区别
Posted
技术标签:
【中文标题】与 django 查询集注释中的先前对象的区别【英文标题】:Difference with previous object in django queryset annotation 【发布时间】:2018-09-13 14:36:25 【问题描述】:假设我有以下模型:
class TestModel(models.Model):
some_integer = models.IntegerField()
我有这个模型的 3 个实例:
TestModel.objects.create(some_integer=100)
TestModel.objects.create(some_integer=50)
TestModel.objects.create(some_integer=20)
我想以某种方式对查询集进行注释以便能够获得以下结果:
for obj in TestModel.objects.annotate(difference=...):
print(obj.difference)
=> 50 # 100 - 50
=> 30 # 50 - 30
=> None # we don't have anything created after this record
是否有机会使用 Django(2.0) 查询集执行此操作,或者我应该在 Python 中“手动”执行此操作?我们可以放心地假设对象是按 pk 或某个日期排序的,因此保留了排序。
【问题讨论】:
我认为概念的问题是标准的关系数据库没有上一个或下一个的概念。元素可以按任何顺序返回,除非元素是明确排序的。 @WillemVanOnsem 我们可以假设 QuerySet 是按 pk 或某个日期排序的,我已经用这些信息更新了描述。 【参考方案1】:基于这个Answer,如果你想使用原始SQL,你可以这样做:
SELECT *,
LEAD("some_integer") OVER(ORDER BY "id") AS "next_val",
"some_integer" - "next_val" AS "difference"
FROM "myapp_testmodel";
但是,从 Django 版本 2.0
开始,您可以使用 Window Functions 创建上述查询:
from django.db.models import Window, F
from django.db.models.functions import Lead
q = TestModel.objects.annotate(
next_val=Window(
expression=Lead('some_integer', offset=1, default=0),
order_by=F('id').asc()
),
difference=F('some_integer')-F('next_val')
)
注意:我已经使用0作为默认值(将应用于最后一项),以简化答案以防止从Integer中减去Null值引起FieldError
。您可以使用 Django 的 Case 查询为最后一项返回 None 。
【讨论】:
谢谢!我从来没有花时间看窗口函数,但我想这会发生在现在:) 如果我只是注释next_val
它工作正常,但如果我在另一个注释中使用 next_val
difference
它会抛出错误:window functions are not allowed in GROUP BY
。我在这里错过了什么?以上是关于与 django 查询集注释中的先前对象的区别的主要内容,如果未能解决你的问题,请参考以下文章