按范围Django获取ID组

时间:2018-08-20 09:58:11

标签: django django-queryset

我有: 型号:

id = PrimaryKey()
value = IntegerField()

我想按1-78-30>30之间的值范围获取ID组的列表。
这样做的有效方式是什么?
或者我应该为每个范围写查询:

one= Model.objects.filter(value__gt=0,value__lte=7).values_list(id)
two= Model.objects.filter(value__gt=7,value__lte=30).values_list(id)
three= Model.objects.filter(value__gt=30).values_list(id)

... 我可以通过aggregate Count这样做吗?我想要最少的数据库事务。

已更新:

实际上是在试图售出多少产品,如果它们很快过期,则每周计数其他月份,例如:

  • 牛奶将在3天后过期。过去3年售出了多少牛奶包 天
  • 面包在7天内过期。在过去7天内售出了多少面包。

此处valueexpires_in,即产品在
过期的天数 (expiry date - mfg date)

模型就像:

发票拆分

product_id
name
desctiption
expires_in

1 个答案:

答案 0 :(得分:1)

使用groupby

如果您需要ids,我们可以使用groupby中的itertools

from itertools import groupby
from operator import itemgetter

def rank(itm):
    vl = itm['value']
    if vl <= 7:
        return 0
    elif vl <= 30:
        return 1
    return 2

dat = {
    k: list(map(itemgetter('id'),v))
    for k, v in groupby(
        Model.objects.filter(value__gt=0).values('id', 'value').order_by('value'),
        rank)
}

现在dat将包含三个元素:0包含1-7范围内的元素列表,1包含8-30范围内的元素,以及2个是id,值大于30。

因此,我们可以通过以下方式获取ids的列表:

dat[0]  # ids with value 1-7
dat[1]  # ids with value 8-30
dat[2]  # ids with value 31+

这将导致一个查询,我们让Python进行分组。如果数据量巨大,这可能会很慢,但由于已经将元素反序列化也需要相当的努力,因此它已经变得相当慢。

优化检查

我们可以让数据库执行确定类别的逻辑,从而将一些工作从Python移至数据库:

from django.db.models import Case, IntegerField, Value

qs = Model.objects.filter(value__gt=0).annotate(
    cat = Case(
        When(value__lt=8, then=Value(0)),
        When(value__lt=31, then=Value(1)),
        default=Value(2),
        output_field=IntegerField(),
    ))
).values('id', 'cat').order_by('cat')

,然后使用以下内容构建字典:

from operator import itemgetter
from itertools import groupby

data = {
    k: list(map(itemgetter('id'), v))
    for k, v in groupby(qs, itemgetter('cat'))
}