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

时间:2009-12-15 16:43:38

标签: python django orm group-by

我真的不知道如何将GROUP BYHAVING翻译成Django的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;

输出:

[(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)]

我的Django模型:

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

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

2 个答案:

答案 0 :(得分:14)

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

Article.objects.values('pub_date').annotate(article_count=Count('title'))

pub_date会group by。但我无法想到在那里内联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()

然后你可以这样做:

Article.objects.values('pub_year', 'pub_month').annotate(article_count=Count('title'))

如果您要执行此操作,我建议您通过覆盖文章的pub_year方法并从pub_month中提取值来自动填充save()pub_date


修改

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

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

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

如果您想出一个自定义模型管理器,并且需要进行此类数据库引擎相关更改,那么这可能并不是那么糟糕。

答案 1 :(得分:2)