【问题标题】:Filtering only on Annotations in Django仅过滤 Django 中的注释
【发布时间】:2010-01-19 19:52:39
【问题描述】:

举个例子: http://docs.djangoproject.com/en/dev/topics/db/aggregation/#filter-and-exclude

Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book'))

有没有办法让过滤器只应用于注释,所以它会返回所有出版商,其中一些出版商的数量为 num_books=0?

【问题讨论】:

  • 那么,您想要一份所有出版商的列表,每个出版商都标有他们的高评价书籍数量吗?
  • 是的,该列表应包括没有书籍或只有低评级书籍的出版商。

标签: django orm


【解决方案1】:

您可以在过滤器中使用注释变量。

publishers=Publisher.objects.annotate(num_books=Count('book')).filter(num_books__gte=2)

【讨论】:

  • 我的意思是,我希望所有出版商都被退回,并且每个出版商都应该标注高评分的书籍数量。因此,出版商列表中应该包括少于两本高评分书籍的出版商,只有低评分书籍的出版商,以及根本没有书籍的出版商。如果我能更好地澄清这一点,请告诉我。
【解决方案2】:

嗯,我认为你必须使用extra clause

Publisher.objects.extra(select={
    'num_books': 'SELECT COUNT(*) ' + \
                 'FROM <your_app>_book ' + \
                 'WHERE <your_app>_book.publisher_id = ' + \
                       '<your_app>_publisher.id AND ' + \
                       'rating > 3.0'
})

【讨论】:

  • 这是迄今为止我看到的最好的答案。如果我不必使用原始 sql,那就太好了。
  • 这是真的!不过,这不应该导致任何兼容性问题。但是请告诉我,如果你发现了一种不用原始 sql 的方法!
  • 您可能可以使用 QuerySet._as_sql(connection) 方法,由 Django 自己生成原始查询。小技巧,但仍然比自己编写更好。
  • @NathanTregillus 它不会创建任何额外的查询,因为它都是在 SQL 中完成的。只是因为查询更复杂,所以速度会慢一些,但没有什么比对每个对象都进行一次查询更慢。
  • 这曾经是一个很好的答案,但在 2017 年已经过时了。django docs for extra 说这种方法已被弃用,只能作为最后的手段使用。他们甚至要求您为您的用例开一张票,以便他们可以通过annotate 支持它。
【解决方案3】:
from django.db import models

Publisher.objects.annotate(
    num_books=models.Sum(
        models.Case(
            models.When(
                book__rating__gt=3.0,
                then=1,
            ),
            default=0,
            output_field=models.IntegerField(),
        )
    )
).filter(
    num_books=0,
)

【讨论】:

  • 看起来很接近,除了最后不要按“num_books=0”过滤。应退回所有发布者。
【解决方案4】:

启动 Django 2.0 可以使用聚合函数的filter参数:

from django.db.models import Q    
Publisher.objects.annotate(num_books=Count('book', filter=Q(book__rating__gt=3.0)))

答案基于cheat sheet

【讨论】:

    【解决方案5】:

    你可以试试这样的:

    Book.objects.values('publisher').annotate(num_books=Count('id'))
    

    【讨论】:

    • 这将是所有书籍的计数,而不仅仅是评分大于 3 的书籍。
    【解决方案6】:

    我刚遇到这种问题。如果我对问题的解释和预期的解决方案是正确的,这就是我的工作解决方案:
    Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0) 只需交换过滤器和注释位置。这是在 Django 1.9 版中完成的

    【讨论】:

    • 这与我的问题中的代码完全相同(甚至没有交换)。我遇到的问题是它没有显示拥有 0 本书的出版商。我根本不想过滤发布者,我只想过滤计数。
    • 对不起,我忘了编辑你的示例代码。但这就是我想在我的查询集中使用过滤器和注释时实现的。不幸的是,我还没有清楚地阅读您关于 0 图书出版商的问题。
    猜你喜欢
    • 2015-01-25
    • 2019-08-17
    • 2015-04-07
    • 2016-04-28
    • 1970-01-01
    • 2011-06-22
    • 2012-04-05
    • 2012-03-07
    • 2015-12-09
    相关资源
    最近更新 更多