与django queryset注释中的先前对象的差异

问题描述 投票:1回答:1

我们假设我有以下模型:

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)

我想以某种方式注释queryset以获得以下结果:

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或某个日期排序,因此保留了排序。

python django django-queryset
1个回答
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作为默认值(将应用于最后一项),以简化从单词中减去Null值导致的FieldError的答案。你可以使用Django的Case查询处理最后一项的返回None。

© www.soinside.com 2019 - 2024. All rights reserved.