如何过滤反向外键字段上的 Django 注释

tru*_*one 3 django django-aggregation

我正在尝试获取具有特定字段值的所有相关模型的计数。

这是一些代码...

模型.py:

class Author(models.Model):
  name = models.CharField(max_length=100)

class Book(models.Model):
  BAD = "BAD"
  MEH = "MEH"
  GOOD = "GOOD"
  GREAT = "GREAT"
  REVIEW_CHOICES = (
    (BAD, BAD.title()),
    (MEH, MEH.title()),
    (GOOD, GOOD.title()),
    (GREAT, GREAT.title()),
  )
  title = models.CharField(max_length=100)
  review = models.CharField(max_length=100, choices=REVIEW_CHOICES)
  author = models.ForeignKey(Author, related_name="books")
Run Code Online (Sandbox Code Playgroud)

假设我想列出每个作者的每种类型评论的数量。

我试过了:

Authors.object.annotate(n_good_books=Count("books")).filter(books__review="GOOD").values("name", "n_good_books")  
Run Code Online (Sandbox Code Playgroud)

我也试过:

Authors.object.annotate(n_good_books=Count("books", filter=Q(books_review="GOOD"))).values("name", "n_good_books")  
Run Code Online (Sandbox Code Playgroud)

但这些都不起作用。

有什么建议?

Wil*_*sem 6

您需要.filter(..) 之前.annotate(..),所以:

Authors.object.filter(
    books__review="GOOD"  # before the annotate
).annotate(
    n_good_books=Count("books")
)
Run Code Online (Sandbox Code Playgroud)

这将导致 a QuerySetof Authors,其中每个Author都有一个.n_good_books包含商品数量的额外属性Book。相反的意思是,您只会检索至少有一个相关人员获得好评的Authors 。如文档中所述Book

与使用annotate()条款,过滤器具有的效果 限制针对其计算出的注释的对象。例如,您可以使用以下查询生成标题以“Django”开头的所有书籍的带注释的列表:

>>> from django.db.models import Count, Avg
>>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors'))
Run Code Online (Sandbox Code Playgroud)

(..)

也可以过滤带注释的值。注释的别名可以像任何其他模型字段一样用在filter()andexclude()子句中。

例如,要生成具有多个作者的书籍列表,您可以发出查询:

>>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)
Run Code Online (Sandbox Code Playgroud)

此查询生成带注释的结果集,然后根据该注释生成过滤器。

Count(..., filter=Q(..))方法只适用以来,所以在,这将无法工作。