【问题标题】:Best way to query Django ORM to sum items by category per year (for time series)查询 Django ORM 以每年按类别汇总项目的最佳方法(对于时间序列)
【发布时间】:2021-06-16 09:27:27
【问题描述】:

假设我们有模型:

class Category(models.Model):
  description = models.CharField(...)  # Ex: 'horror', 'classic', 'self-help', etc.


class Book(models.Model):
  category = models.ForeignKey(Category, ...)
  written_date = models.DateField(...)

我想做一个查询,最终得到我每年每个类别的图书总数!像这样:

{
  '2019-01-01': { 'horror': 2, 'classic': 1},
  '2020-01-01': { 'horror': 2, 'classic': 1, 'self-help': 4},
  ...
}

我只能提出以下查询:

Book.objects \
.annotate(year=TruncYear('written_date')) \
.values('year', 'category__description') \
.order_by('year') \
.annotate(total=Count('id'))

但这只会让我明白

{
    {
        "category__description": "Horror",
        "year": "2019-01-01",
        "total": 2
    },
    {
        "category__description": "Classic",
        "year": "2019-01-01",
        "total": 1
    },
    {
        "category__description": "Horror",
        "year": "2020-01-01",
        "total": 2
    },
    ...
}

有没有办法通过 ORM 做到这一点?或者我必须通过直接操作结果来做到这一点?谢谢!

【问题讨论】:

  • 不要真的相信有任何 ORM 解决方案(事实上,即使您查看 SQL,也只会得到表格结果)。您可以在视图中执行分组(Willem 的解决方案),在模板中使用regroup template tag 进行分组,或者使用ifchanged template tag 给出分组的错觉。我建议使用威廉的解决方案。

标签: python sql django orm


【解决方案1】:

您可以使用groupby [python-doc] 对结果进行后处理:

from itertools import groupby
from operator import itemgetter

data = Book.objects.values(
    'category__description'
    year=TruncYear('written_date'),
).annotate(
    total=Count('id')
).order_by('year', 'category__description')

result = {
    yrs: {r['category__description']: r['total'] for r in rs}
    for yrs, rs in groupby(data, itemgetter('year'))
}

【讨论】:

  • 这行得通!如果几天后没有更好的 ORM 路线,将接受
猜你喜欢
  • 1970-01-01
  • 2021-05-05
  • 1970-01-01
  • 2016-09-12
  • 2021-04-30
  • 2018-05-15
  • 1970-01-01
  • 1970-01-01
  • 2019-04-26
相关资源
最近更新 更多