在Django中按日期计算记录数

Posted

技术标签:

【中文标题】在Django中按日期计算记录数【英文标题】:Count number of records by date in Django 【发布时间】:2011-01-17 16:43:15 【问题描述】:

我有一个类似于以下的模型:

class Review(models.Model):
    venue = models.ForeignKey(Venue, db_index=True)
    review = models.TextField()  
    datetime_created = models.DateTimeField(default=datetime.now)

我想查询数据库以获取按天分组的场所的评论总数。 mysql 查询将是:

SELECT DATE(datetime_created), count(id) 
FROM REVIEW 
WHERE venue_id = 2
GROUP BY DATE(datetime_created);

在 Django 中完成此任务的最佳方法是什么?我可以使用

Review.objects.filter(venue__pk=2)

并在视图中解析结果,但这对我来说似乎不正确。

【问题讨论】:

Django: Group by date (day, month, year)的可能重复 【参考方案1】:

现在Extra() 正在贬值,更合适的答案是使用Trunc,例如this accepted answer

现在OP的问题将回答如下

from django.db.models.functions import TruncDay

Review.objects.all()
    .annotate(date=TruncDay('datetime_created'))
    .values("date")
    .annotate(created_count=Count('id'))
    .order_by("-date")

【讨论】:

缺少括号? .annotate(date=TruncDay('datetime_created') 2021 年仍然有效!【参考方案2】:

你也可以定义自定义函数:

from django.db.models.expressions import Func

# create custom sql function
class ExtractDateFunction(Func):
    function = "DATE" # thats the name of function, the way it mapped to sql

# pass this function to annotate
Review.objects.filter(venue__pk=2)
      .annotate(date_created=ExtractDateFunction("datetime_created"))
      .values('date_created')
      .annotate(created_count=Count('id'))

只要确保你的数据库引擎支持 DATE 函数

【讨论】:

此处定义的 ExtractDateFunction 不支持时区修改,如下所示:docs.djangoproject.com/en/1.11/ref/models/database-functions 您可以使用 TruncDate 获取尊重时区的查询,从 1.10 开始(请参阅该链接)反而。 (如here)【参考方案3】:

为了完整起见,由于 extra() 旨在弃用,因此可以使用这种方法:

from django.db.models.expressions import DateTime

Review.objects.all().\
    annotate(month=DateTime("timestamp", "month", pytz.timezone("Etc/UTC"))).\
    values("month").\
    annotate(created_count=Count('id')).\
    order_by("-month")

它在 django 1.8 中对我有用,在 sqlite 和 MySql 数据库中。

【讨论】:

你也可以使用 django timezone utils 代替 pytz.timezone django.utils.timezone.get_default_timezone 这似乎已在 Django 1.10 中移动到 Extract 下【参考方案4】:

如果您要存储日期字段,则可以使用:

from django.db.models import Count

Review.objects.filter(venue__pk = 2)
    .values('date').annotate(event_count = Count('id'))

因为您要存储日期时间,所以它有点复杂,但这应该是一个很好的起点。查看聚合文档here。

【讨论】:

【参考方案5】:

这应该可以工作(使用您使用的相同的 MySQL 特定功能):

Review.objects.filter(venue__pk=2)
    .extra('date_created' : "date(datetime_created)")
    .values('date_created')
    .annotate(created_count=Count('id'))

【讨论】:

这就像我的回答,但更好! 遗憾地错过了 .extra().. 非常强大。谢谢! 我无法得到它的东西,,,在 .values() 之前使用 .extra() 得到不同的结果,然后在 .values() 子句之后使用它?!!有没有高手解释一下?! 我在这里有点晚了@radev,但这是您正在寻找的答案:“如果您在 extra() 调用之后使用 values() 子句,则选择参数定义的任何字段在 extra() 中必须明确包含在 values() 调用中。在 values() 调用之后进行的任何 extra() 调用都将忽略其额外的选定字段。 docs.djangoproject.com/en/1.7/ref/models/querysets 对,这是values() clause 的某种神秘行为的结果。 BUT 还请记住,在应用了排序的查询集中使用它(通过查询集的 order_by() 部分或在默认排序中使用的字段)模型)在您明确清除查询中的任何顺序之前不会工作 -docs.djangoproject.com/en/dev/topics/db/aggregation/…

以上是关于在Django中按日期计算记录数的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Looker 中按日期计算状态变化?

仅计算给定日期的新记录数(如果它们是新记录)

在R中按组计算日期之间的差异

记录数正确显示,但当日期是相当旧的日期时,“新计算开始日期”列显示所有“######”格式,例如:01-DEC-1184

根据上次更新日期计算记录数 + null

如何计算几个日期之间的记录数