Фильтрация только на аннотации в Django

Взяв пример из: 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

Hm, я думаю, вы должны использовать дополнительное предложение:

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'
})

Ответ 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,
)

Ответ 4

Вы можете попробовать что-то вроде:

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

Ответ 5

Я просто столкнулся с такой проблемой. И если моя интерпретация проблемы и ожидаемое решение верны, это мое рабочее решение:
Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0) Просто поменяйте фильтр и отметьте позицию. Это сделано в Django версии 1.9

Ответ 6

Начиная с Django 2.0 можно использовать параметр filter функции агрегирования:

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

Ответ основан на шпаргалке.