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

时间:2018-09-24 16:29:46

标签: django django-aggregation

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

这是一些代码...

models.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")

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

我尝试过:

Authors.object.annotate(n_good_books=Count("books")).filter(books__review="GOOD").values("name", "n_good_books")  

我也尝试过:

Authors.object.annotate(n_good_books=Count("books", filter=Q(books_review="GOOD"))).values("name", "n_good_books")  

但是这些都不起作用。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

您需要在.filter(..)之前.annotate(..)

Authors.object.filter(
    books__review="GOOD"  # before the annotate
).annotate(
    n_good_books=Count("books")
)

这将导致QuerySetAuthor中的Author,其中每个.n_good_books都有一个额外的属性Book,其中包含有效Author的数量。相反的意思是,您<仅> 将检索{<1>至少个相关Book经过了良好审查的annotate()。就像specified in the documentation

  

>>> from django.db.models import Count, Avg >>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors')) 子句一起使用时,过滤器具有以下作用:   约束要为其计算注释的对象。例如,您可以生成所有带有注释的书的带注释的列表   使用查询以“ Django”开头的标题:

filter()
     

(..)

     

注释值也可以过滤。注释的别名可在以下位置的exclude()>>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1) 子句中使用   与其他模型字段相同。

     

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

Count(..., filter=Q(..))
     

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

public class CountryData : INotifyPropertyChanged { private string countryName; public string CountryName { get { return countryName; } set { countryName = value; RaisePropertyChanged("CountryName"); } } public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string prop) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } } 方法仅自起起作用,因此在中这将无效

答案 1 :(得分:0)

@ willem-van-onsem对我提出的问题有正确的答案。

但是,如果我想一次获得所有书籍类型的计数,我可以做类似的事情:

from django.db.models import Case, When, IntegerField

Authors.object.annotate(
  n_bad_books=Count(Case(When(books__review="BAD", then=1), output_field=IntegerField())),
  n_meh_books=Count(Case(When(books__review="MEH", then=1), output_field=IntegerField())),
  n_good_books=Count(Case(When(books__review="GOOD", then=1), output_field=IntegerField())),
  n_great_books=Count(Case(When(books__review="GREAT", then=1), output_field=IntegerField())),
)

他是对的,这非常优雅。