我有: 型号:
id = PrimaryKey()
value = IntegerField()
我想按1-7
和8-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
这样做吗?我想要最少的数据库事务。
实际上是在试图售出多少产品,如果它们很快过期,则每周计数其他月份,例如:
此处value
是expires_in
,即产品在
过期的天数
(expiry date - mfg date)
模型就像:
发票拆分
product_id
name
desctiption
expires_in
答案 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'))
}