Django和条件聚合

时间:2010-05-20 15:15:38

标签: python django aggregate

我有两个模特,作者和文章:

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的aggregates是一块蛋糕。问题是,它应该只计算已发布的文章。根据Django票务跟踪器中的ticket 11305,这还不可能。我尝试使用该票证中提到的CountIf注释,但它没有引用日期时间字符串,也没有进行所需的所有连接。

那么,除了编写自定义SQL之外,最好的解决方案是什么?

3 个答案:

答案 0 :(得分:5)

您可以使用受django-aggregate-if启发的ticket 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'})

答案 1 :(得分:4)

Django 1.8+解决方案

自Django 1.8起,conditional expressions可用于构建查询集。

有关详细信息,请参阅文档,但您的问题的快速解决方案如下所示:

today = datetime.date.today()
authors = Author.objects.all().annotate(article_count=Sum(
    Case(When(articles__pubdate__lt=today, then=1),
         output_field=IntegerField())
))

我虽然没有检查,但它应该有用。

答案 2 :(得分:1)

我通过创建一个包含所需GROUP BY语句的SQL视图,以及一个包含managed = FalseOneToOneFieldAuthor表的视图的模型来解决我的问题。它不是最有效或最优雅的解决方案,但它可以正常工作。