Django与条件聚合
我有两个模型,一个是作者(authors),另一个是文章(articles):
class Author(models.Model):
name = models.CharField('name', max_length=100)
class Article(models.Model)
title = models.CharField('title', max_length=100)
pubdate = models.DateTimeField('publication date')
authors = models.ManyToManyField(Author)
现在我想要选出所有的作者,并且给他们加上各自发表文章的数量。这在Django中用聚合函数来做非常简单。不过问题是,我只想统计那些已经发布的文章。根据Django的一个问题追踪记录ticket 11305,目前还做不到这一点。我尝试使用那个记录中提到的CountIf
注释,但它没有正确处理日期时间字符串,也没有进行所有需要的连接操作。
那么,除了写自定义的SQL代码,还有什么好的解决办法呢?
3 个回答
1
我通过创建一个SQL视图来解决了我的问题,这个视图里包含了需要的GROUP BY
语句。然后我为这个视图建立了一个模型,并设置了managed = False
,同时还添加了一个指向Author
表的OneToOneField
。虽然这不是最有效或最优雅的解决方案,但它能正常工作。
5
你可以使用这个叫做 django-aggregate-if 的应用,它的灵感来源于 11305号问题。或者,你也可以直接使用 extra
方法来处理查询集(假设你的应用叫“articles”):
Author.objects.all().extra(
select={'article_count': 'SELECT COUNT(*) FROM "articles_article" '
'INNER JOIN "articles_article_authors" '
'ON "articles_article"."id" = '
' "articles_article_authors"."article_id" '
'WHERE "articles_article_authors"."author_id" = '
' "articles_author"."id" '
'AND "articles_article"."pubdate" IS NOT NULL'})
4
Django 1.8及以上版本的解决方案
从Django 1.8开始,条件表达式可以用来构建查询集。
想了解更多细节可以查看文档,不过针对你的问题,快速的解决方案大概是这样的:
today = datetime.date.today()
authors = Author.objects.all().annotate(article_count=Sum(
Case(When(articles__pubdate__lt=today, then=1),
output_field=IntegerField())
))
我没有实际测试过,但应该是可以用的。