【问题标题】:Django annotate groupings by monthDjango 按月注释分组
【发布时间】:2011-04-02 09:14:01
【问题描述】:

我有一个非常基本的模型:

class Link(models.Model):
    title = models.CharField(max_length=250, null=False)
    user = models.ForeignKey(User)
    url = models.CharField(max_length=250, blank=True, null=True)
    link_count = models.IntegerField(default=0)
    pub_date = models.DateField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

我可以使用以下方法创建按日期分组的所有条目的列表:

Link.objects.values('pub_date').order_by('-pub_date').annotate(dcount=Count('pub_date'))

这自然会按天对项目进行分组。但我真正想做的是按月分组。无论如何我可以使用 annotate() 来做到这一点吗?

非常感谢,

G

【问题讨论】:

标签: python django


【解决方案1】:

如果您使用的是 PostgreSQL,以下方法可能有效:

from django.db.models import Count

Link.objects.extra(select={'month': 'extract( month from pub_date )'}).values('month').annotate(dcount=Count('pub_date'))

我不确定extract 在其他数据库中的可移植性。

【讨论】:

  • 谢谢!这似乎也适用于 mySQL。除了这组任何一年中的所有月份。我正在尝试将每年的月份分组。但这是一个很好的开始,所以我会调整。再次感谢。
  • 您可以在其中添加一个过滤器,将日期限制在特定范围内。 .filter(pub_date__gte=datetime.datetime(fill in date here))
  • 使用 connection.ops.date_trunc_sql('month', 'date') 而不是硬编码的提取 SQL 将使语句与其他后端兼容
【解决方案2】:
from django.db import connections
from django.db.models import Count

Link.objects.extra(select={'month': connections[Link.objects.db].ops.date_trunc_sql('month', 'pub_date')}).values('month').annotate(dcount=Count('pub_date'))

【讨论】:

  • 注意,还必须导入from django.db.models import Count
【解决方案3】:

添加,作为使用extra() 的替代方案:从 Django 1.8 开始,您还可以使用条件表达式。

>>> year_overview = Link.objects.filter(pub_date__year=year).aggregate(
    jan=Sum(
        Case(When(created__month=0, then=1),
             output_field=IntegerField())
    ),
    feb=Sum(
        Case(When(created__month=1, then=1),
             output_field=IntegerField())
    ),
    mar=Sum(
        Case(When(created__month=2, then=1),
             output_field=IntegerField())
    ),
    apr=Sum(
        Case(When(created__month=3, then=1),
             output_field=IntegerField())
    ),
    may=Sum(
        Case(When(created__month=4, then=1),
             output_field=IntegerField())
    ),
    jun=Sum(
        Case(When(created__month=5, then=1),
             output_field=IntegerField())
    ),
    jul=Sum(
        Case(When(created__month=6, then=1),
             output_field=IntegerField())
    ),
    aug=Sum(
        Case(When(created__month=7, then=1),
             output_field=IntegerField())
    ),
    sep=Sum(
        Case(When(created__month=8, then=1),
             output_field=IntegerField())
    ),
    oct=Sum(
        Case(When(created__month=9, then=1),
             output_field=IntegerField())
    ),
    nov=Sum(
        Case(When(created__month=10, then=1),
             output_field=IntegerField())
    ),
    dec=Sum(
        Case(When(created__month=11, then=1),
             output_field=IntegerField())
    ),
)

>>> year_overview
{'mar': None, 'feb': None, 'aug': None, 'sep': 95, 'apr': 1, 'jun': None, 'jul': None, 'jan': None, 'may': None, 'nov': 87, 'dec': 94, 'oct': 100}

【讨论】:

  • 使用最新的 Django 版本,我想这是推荐的解决方案
【解决方案4】:

我听说.extra() 将来会被弃用。他们建议改用Func 对象。还有一个可以提取一个月而不使用痛苦的Case 语句。

from django.db.models.functions import ExtractMonth
Link.objects.all().annotate(pub_date_month=ExtractMonth('pub_date'))

【讨论】:

    猜你喜欢
    • 2016-09-20
    • 2014-03-17
    • 1970-01-01
    • 2020-01-26
    • 2018-04-19
    • 2019-11-04
    • 1970-01-01
    • 1970-01-01
    • 2016-12-10
    相关资源
    最近更新 更多