仅过滤 Django 中的注释
Posted
技术标签:
【中文标题】仅过滤 Django 中的注释【英文标题】:Filtering only on Annotations in 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?
【问题讨论】:
那么,您想要一份所有出版商的列表,每个出版商都标有他们的高评价书籍数量吗? 是的,该列表应包括没有书籍或只有低评级书籍的出版商。 【参考方案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 图书出版商的问题。以上是关于仅过滤 Django 中的注释的主要内容,如果未能解决你的问题,请参考以下文章