Django ORM,按天分组

35

我试图按照日期对产品进行分组,但是date_created是一个datetime字段。

Product.objects.values('date_created') \
               .annotate(available=Count('available_quantity'))

返回值:

[
    {'date_created': datetime.datetime(2012, 4, 14, 13, 3, 6), 'available': 1},
    {'date_created': datetime.datetime(2012, 4, 14, 17, 12, 9), 'available': 1},
    ...
]

我想要:

[
    {'date_created': datetime.datetime(2012, 4, 14), 'available': 2}, ...
]

编辑:数据库后端 MYSQL


是的,我想要类似于 [{'today': 17}, {'yesterday': 21}, 等等] 的东西。 - Hedde van der Heide
5个回答

45

这个问题的启发,尝试在MySQL中使用以下方法:

from django.db.models import Count

Product.objects.extra(select={'day': 'date( date_created )'}).values('day') \
               .annotate(available=Count('date_created'))

2
这很有帮助,但我不得不在values()和annotate()之间使用一个明确的order_by()来清除默认排序。请参见https://docs.djangoproject.com/en/dev/topics/db/aggregation/#interaction-with-default-ordering-or-order-by。谢谢! - somecallitblues
奇怪...即使是相同的日期,我仍然有多个字段没有被分组计数...我尝试了下面的解决方案,使用to_char并将我的数据库从sqlite更改为postgres,但当运行available = Count('date_created')时,它仍然考虑了日期时间。 - Diego Vinícius

6

San4ez的回答类似,但返回日期为“YYYY-MM-DD”,而不是“datetime.datetime(YYYY,MM,DD)”:

Product.objects.extra(select={'day': "TO_CHAR(date_created, 'YYYY-MM-DD')"})
               .values('day') \
               .order_by('day') \
               .annotate(available=Count('date_created'))

1
返回的查询集以更易读的格式呈现,感谢您的回答。这比@San4ez建议的更好。 - Simran

1
在Django 1.4中,您可以使用.dates('date_created', 'day')代替.values()
尝试以下代码片段:
Product.objects.annotate(available=Count('available_quantity')) \
  .dates('date_created', 'day')

这个应该返回:

[
    {'date_created': datetime.datetime(2012, 4, 14), 'available': 2}, ...
]

听起来很接近,但我只得到了一个日期列表: [datetime.datetime(2012, 4, 10, 0, 0), datetime.datetime(2012, 4, 10, 0, 0), datetime.datetime(2012, 4, 10, 0, 0), datetime.datetime(2012, 4, 10, 0, 0)] - Hedde van der Heide
在使用 .dates 之前,请尝试使用 .annotate() 创建 DateQuerySet。 - cfedermann
只需要日期,对我来说一样。 - linqu

0

通过遵循San4ez的答案和Zanon的更改

对我来说,我不得不做一个解决方法来与Postgres或Sqlite一起工作,因为Count()函数将考虑datetime字段,而无论您是否使用日期创建了一个“day”输入,因为date_created仍然持有时间信息,所以具有多个记录的时间不会合并和计算,经过尝试许多不同的方法,我达到了跳过时间的方式。

Django 2.2

from django.db.models import Count

# Change date() to to_char(created_at, 'YYYY-MM-DD') if using Postgres
Product.objects.extra(select={'day': 'date( date_created )'})\
    .values('day') \
    .order_by('date_created__date')\
    .annotate(available=Count('date_created__date'))

0

你可以尝试一下

Product.objects.extra(select={'day': "TO_CHAR(date_created, 'YYYY-MM-DD')"})\
                .values('day')\
                .order_by('day')\
                .annotate(bets=Count('date_created'))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接