按范围Django获取ID组 [英] get ids group by range django

查看:125
本文介绍了按范围Django获取ID组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有:
模型:

  id = PrimaryKey()
value = IntegerField()

我想按 1-之间的值范围获取ID组列表7 8-30 > 30

有效的方式是什么?

或者我应该为每个范围编写查询,例如:

  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)
三个= Model.objects.filter(value__gt = 30).values_list(id)

...
我可以通过总计数这样做吗?我想要最少的数据库交易。



已更新:



实际上是在尝试售出多少产品,如果它们很快就会过期,然后每周计数一次,每月一次,就像:




  • 牛奶在3天后过期。过去3天
    天售出多少牛奶包

  • 面包在7天后过期。在过去7天内售出了多少面包。




其中 expires_in ,即产品在

(到期日期-制造日期)



模型如下:



发票折抵

  product_id 
名称
便笺
expires_in


解决方案

groupby



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

 来自itertools import groupby 
来自运营商进口itemgetter

def rank( itm):
vl = itm ['value']
如果vl< = 7:
返回0
elif vl< = 30:
返回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 表示元素<$ c $ 8-30 和 2 c> id s的值为30 +。



因此,我们可以获取 ids ,其中:

  dat [0]#值为1-7的id 
dat [1]# ID值8-30
dat [2]#ID值31+

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



优化检查



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



<来自django.db.models的pre> 导入大小写,IntegerField,值

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运算符import itemgetter来自itertools import groupby的


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


I have: Model:

id = PrimaryKey()
value = IntegerField()

I would like to get list of ids group by value range between 1-7 and 8-30 and >30.
What would be the efficient way to do so?
Or shall I write query for each range like:

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)

... can I do so via aggregate Count? I want minimum database transactions.

Updated:

Actually am trying to get how many products are sold, If they expires soon, then weekly count else monthly like:

  • Milk expires in 3 days. How many milk packets were sold in past 3 days
  • Bread expires in 7 days. How many bread were sold in past 7 days.

here value is expires_in i.e. in how many days a product expires in
(expiry date - mfg date)

Model is like:

InvoiceBreakup

product_id
name
desctiption
expires_in

解决方案

With groupby

If you need the ids, we can use groupby of itertools for this:

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)
}

Now dat will contain three elements: 0 contains the list of elements in the range of 1-7, 1 for elements in the range 8-30 and 2 in are ids with value 30+.

We can thus then obtain the list of ids, with:

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

This will result in a single query, and we let Python do the grouping. This can be slow if the data is huge, but it will already get quite slow, since the deserializing of the elements also will take comparable effort.

Optimizing the checks

We can let the database perform the logic to determine the category, and thus move some work from Python to the database:

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')

and then construct the dictionary with:

from operator import itemgetter
from itertools import groupby

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

这篇关于按范围Django获取ID组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆