如何在Django的ORM中使用注释和聚合进行GROUP BY查询

Ben*_*end 5 python django orm group-by

我真的不知道如何翻译GROUP BYHAVINGDjango QuerySet.annotateQuerySet.aggregate.我正在尝试将此SQL查询转换为ORM说话

SELECT EXTRACT(year FROM pub_date) as year, EXTRACT(month from pub_date) as month, COUNT(*) as article_count FROM articles_article GROUP BY year,month;
Run Code Online (Sandbox Code Playgroud)

输出这个:

[(2008.0, 10.0, 1L), # year, month, number of articles
(2009.0, 2.0, 1L),
(2009.0, 7.0, 1L),
(2008.0, 5.0, 3L),
(2008.0, 9.0, 1L),
(2008.0, 7.0, 1L),
(2009.0, 5.0, 1L),
(2008.0, 8.0, 1L),
(2009.0, 12.0, 2L),
(2009.0, 3.0, 1L),
(2007.0, 12.0, 1L),
(2008.0, 6.0, 1L),
(2009.0, 4.0, 2L),
(2008.0, 3.0, 1L)]
Run Code Online (Sandbox Code Playgroud)

我的Django模型:

class Article(models.Model):
    title = models.CharField(max_length=150, verbose_name=_("title"))
    # ... more 
    pub_date = models.DateTimeField(verbose_name=_('publishing date'))
Run Code Online (Sandbox Code Playgroud)

这个项目应该在几个不同的数据库系统上运行,所以我试图尽可能远离纯SQL.

cet*_*eek 14

我想在一个查询中执行此操作,您可能需要将月份和年份作为单独的字段...

Article.objects.values('pub_date').annotate(article_count=Count('title'))
Run Code Online (Sandbox Code Playgroud)

那将group by是pub_date.但是我无法想到在extract那里内联函数子句.

如果您的模型是:

class Article(models.Model):
    title = models.CharField(max_length=150, verbose_name=_("title"))
    # ... more 
    pub_date = models.DateTimeField(verbose_name=_('publishing date'))
    pub_year = models.IntegerField()
    pub_month = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

Article.objects.values('pub_year', 'pub_month').annotate(article_count=Count('title'))
Run Code Online (Sandbox Code Playgroud)

如果你要做到这一点,我建议有pub_yearpub_month通过覆盖自动填充save()的物品的方法,并从提取的值pub_date.


编辑:

一种方法是使用额外的 ; 但它不会授予您数据库独立性......

models.Issue.objects.extra(select={'year': "EXTRACT(year FROM pub_date)", 'month': "EXTRACT(month from pub_date)"}).values('year', 'month').annotate(Count('title'))
Run Code Online (Sandbox Code Playgroud)

虽然这可行,但我认为(未经测试),extra如果您更改数据库服务器,它将要求您修改字段.例如,在SQL Server中你会做year(pub_date)而不是extract(year from pub_date)...

如果你提出一个自定义模型管理器,你突出标记为需要这样的数据库引擎相关更改,这可能不是那么糟糕.