Django:按组

时间:2017-01-24 18:48:40

标签: python mysql django aggregate

我有以下Django模型:

class Costs(models.Model):
  """Represents a cost for a vendor / locale combo."""
  valid_from_date = models.DateField()
  vendor_id = models.ForeignKey('Vendor')
  locale_id = models.ForeignKey('Locale')
  cost = models.FloatField()

为了保留历史数据,当供应商/区域设置组合的成本发生变化时,我们只需使用新的valid_from_date向表中添加新条目(而不是覆盖旧条目)。

使用Costs.objects.all()从表格中获取所有数据相当容易。使用Costs.objects.filter(vendor_id=1, locale_id=10).latest()获取单个供应商/区域设置的当前值也很容易。

我感兴趣的是每个供应商/区域设置组合的所有最新成本值。因此,基本上在每个组合上运行latest()函数并获得结果列表/查询集。

例如,给定以下数据集:

  • Id:100,日期:2017-1-1,供应商:1,区域设置:10,费用:$ 1
  • Id:200,日期:2017-2-1,商家:1,区域设置:10,费用:$ 2
  • Id:300,日期:2017-1-1,商家:2,区域设置:10,费用:$ 3
  • Id:400,日期:2017-2-1,商家:2,区域设置:10,费用:$ 4
  • Id:500,日期:2017-1-1,商家:2,区域设置:20,价格:$ 5

我希望得到以下数据:

  • Id:200,日期:2017-2-1,商家:1,区域设置:10,费用:$ 2
  • Id:400,日期:2017-2-1,商家:2,区域设置:10,费用:$ 4
  • Id:500,日期:2017-1-1,商家:2,区域设置:20,价格:$ 5

我已多次阅读aggregation docs,但似乎无法找到完全匹配的内容。

我正在使用带有MySQL后端的Django 1.10。

有什么想法吗?谢谢。

2 个答案:

答案 0 :(得分:1)

如果你有postgres作为后端,你可以使用一些distinct('vendor_id', 'locale_id')并且开心。如果你不这样做,你必须更有创意:

from django.db.models import Max

ids = Costs.objects.\
    values('vendor_id', 'locale_id').\  # grouping based on values will be used for annotation
    annotate(mx=Max('id')).\      # annotate the max id for each group
    order_by().\                  # clear any default ordering to avoid a total mess
    values_list('mx', flat=True)  # retrieve all the max ids

costs = Costs.objects.filter(id__in=ids)  

此shuold导致单个数据库查询。所有这些都可以从docs on the interaction of values, order_by, and annotate; - )

中艰难地提取出来

答案 1 :(得分:0)

我最终直接用Python做了。我将所有内容分组到一个列表字典中(键是供应商/区域设置组合),然后从每个列表中取出最大值。基本上,这个:

groups = collections.defaultdict(list)
for cost in Cost.objects.all():
  groups['{} {}'.format(cost.vendor_id, cost.locale_id].append(cost)
return [max(value, key=operator.attrgetter('date'))
        for value in groups.itervalues()]