Так же просто, как 1,2,3 с Фильтрация аннотаций :
from django.db.models import Count
Person.objects.annotate(count_book=Count('book')).filter(count_book__gt=0)
Для любопытства я сгенерировал SQL для каждого из способов, предложенных в этой теме:*
In [9]: Person.objects.annotate(count_book=Count('book')).filter(count_book__gt=0)
DEBUG (0.000) SELECT "testapp_person"."id", "testapp_person"."name", COUNT("testapp_book_author"."book_id") AS "count_book" FROM "testapp_person" LEFT OUTER JOIN "testapp_book_author" ON ("testapp_person"."id" = "testapp_book_author"."person_id") GROUP BY "testapp_person"."id", "testapp_person"."name", "testapp_person"."id", "testapp_person"."name" HAVING COUNT("testapp_book_author"."book_id") > 0 LIMIT 21; args=(0,)
Out[9]: [<Person: Person object>]
In [10]: Person.objects.exclude(book=None)
DEBUG (0.000) SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" WHERE NOT (("testapp_person"."id" IN (SELECT U0."id" FROM "testapp_person" U0 LEFT OUTER JOIN "testapp_book_author" U1 ON (U0."id" = U1."person_id") LEFT OUTER JOIN "testapp_book" U2 ON (U1."book_id" = U2."id") WHERE (U2."id" IS NULL AND U0."id" IS NOT NULL)) AND "testapp_person"."id" IS NOT NULL)) LIMIT 21; args=()
Out[10]: [<Person: Person object>]
In [11]: Person.objects.filter(pk__in=Book.objects.values_list('author').distinct())
DEBUG (0.000) SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" WHERE "testapp_person"."id" IN (SELECT DISTINCT U1."person_id" FROM "testapp_book" U0 LEFT OUTER JOIN "testapp_book_author" U1 ON (U0."id" = U1."book_id")) LIMIT 21; args=()
Out[11]: [<Person: Person object>]
Может быть, это поможет вам выбрать.
Персонально, я предпочитаю версию Криса, потому что она самая короткая.С другой стороны, я не знаю наверняка о влиянии наличия подзапросов, которое имеет место для двух других способов.Тем не менее, они демонстрируют интересные концепции QuerySet:
Annonation , агрегирование по значению набора запросов.Если вы используете агрегат (Count ('book')), то вы получите общее количество книг.Если вы используете annotate (Count ('book')), то вы получите общее количество книг на значение набора запросов (на человека).Кроме того, у каждого человека есть атрибут count_book , что довольно круто: Person.objects.annotate(count_book=Count('book')).filter(count_book__gt=0)[0].count_book
Подзапросы , что очень полезно для создания сложных запросов.или оптимизировать запросы (например, объединить наборы запросов, например, предварительную выборку общих отношений).