【问题标题】:Django - filter queryset until Sum is reachedDjango - 过滤查询集直到达到 Sum
【发布时间】:2021-12-06 16:28:34
【问题描述】:

让我们想象一个名为Roll 的模型。它存储滚动六面骰子的结果(D6):

class Roll(models.Model):
    outcome = models.PositiveSmallIntegerField('Roll', null=False, blank=False, default=1)

有很多卷,例如:

print(list(Roll.objects.all().values_list('outcome', flat=True)))
>>> [1, 5, 6, 3, 5, 4, 4, 3, 2]

现在,我应该如何获取最新的 N 行,其 Sum('outcome') 达到任意数量,而不以某种方式循环,直到达到该数量?

如果我们想象卷:

pk    | outcome | (accumulated sum)
1     | 3       | 3
2     | 2       | 5
3     | 6       | 11
4     | 1       | 12
5     | 5       | 17
6     | 4       | 21
7     | 3       | 24
8     | 4       | 29
9     | 5       | 34
10    | 1       | 35

和任意数量20,则查询应选择pk 6,因为累计总和现在已达到所需数量。

类似下面的东西可以工作吗?:

amount = 100
Roll.objects.annotate(
    accumulated_sum=Subquery(
        Roll.objects.filter(
            pk__lte=OuterRef('pk')
        ).values('pk').order_by('pk').annotate(
            sum=Sum('outcome', distinct=True)
        ).values(
            'sum'
        )[:1]
    )
).filter(
    accumulated_sum__gte=amount
)

【问题讨论】:

  • 您在注释accumulated_sum时遇到问题吗?
  • 显然是的 :-)
  • 你用的是什么数据库?
  • mysql 8.x (+min text padding)

标签: python django sum annotations


【解决方案1】:

这可能有助于注释 accumuated_sum:

from django.db.models import Subquery, IntegerField

class SQSum(Subquery):
    output_field = IntegerField()
    template = "(SELECT sum(outcome) from (%(subquery)s) _sum)"

accumulated_subquery = SQSum(
    Roll.objects.filter(
        pk__lte=OuterRef('pk')
    ).values("outcome")
)

Roll.objects.annotate(accumulated_sum=accumulated_subquery).filter(accumulated_sum__gte=amount)

【讨论】:

  • 谢谢 -- 任何方法都可以获得相同的结果而无需子类化 Subquery?
  • 不抱歉。别无他法。您对子查询有什么问题吗?
猜你喜欢
  • 2011-10-29
  • 2020-08-22
  • 2019-04-15
  • 2011-09-29
  • 2011-08-12
  • 2019-03-16
相关资源
最近更新 更多