我真的不知道如何将 GROUP BY
和 HAVING
翻译成 Django 的 QuerySet.annotate
和 QuerySet.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。
最佳答案
我认为要在一个查询中执行此操作,您可能必须将月份和年份作为单独的字段...
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'))
如果您要这样做,我建议通过覆盖 save()
方法自动填充 pub_year
和 pub_month
文章并从 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)
...
如果您想出一个自定义模型管理器,并显着标记为需要此类依赖于数据库引擎的更改,这可能还不错。
关于python - 如何使用注释和聚合在 Django 的 ORM 中执行此 GROUP BY 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1908741/