Фильтр Django по количеству аннотированных внутри подзапроса - PullRequest
0 голосов
/ 12 января 2019

Вот абстрактный и упрощенный пример.

Скажем, я хочу получить авторов и аннотировать минимальное количество книг в категории, если оно больше трех.

Книжная и авторская модели и не связаны с полями ForeignKey (помните, абстрактно и упрощенно, есть причина):

Author(models.Model):
    name = models.CharField(max_length=250)

Book(models.Model):
    author_name = models.CharField(max_length=250)
    book_category = models.CharField(max_length=250)

Вот самый простой запрос, который я могу воспроизвести:

(Author.objects
 .annotate(min_valuable_count=Subquery(
    Book.objects
        .filter(author_name=OuterRef('name'))
        .annotate(cnt=Count('book_category'))
        .filter(cnt__gt=3)
        .order_by('cnt')
        .values('cnt')[:1],
    output_field=models.IntegerField()
 ))
)

И я получаю ошибку:

psycopg2.ProgrammingError: missing FROM-clause entry for table "U0"
LINE 1: ... "core_author" GROUP BY "core_author"."id", "U0"."id" ...
                                                       ^

Вот SQL:

SELECT "core_author"."id", "core_author"."name", (
    SELECT COUNT(U0."book_category") AS "cnt" 
    FROM "core_book" U0 WHERE U0."id" = ("core_author"."chat_id") 
    GROUP BY U0."id" HAVING COUNT(U0."book_category") > 3 
    ORDER BY "cnt" ASC  LIMIT 1) 
AS "min_valuable_count" 
FROM "core_author" 
GROUP BY "core_author"."id", "U0"."id"

Обновление № 1

Я обнаружил, что удаление .filter(cnt__gt=3) удаляет последние GROUP BY, которые не имеют доступа к U0:

SELECT "core_author"."id", "core_author"."name", (
    SELECT COUNT(U0."book_category") AS "cnt" 
    FROM "core_book" U0 WHERE U0."id" = ("core_author"."chat_id") 
    GROUP BY U0."id"
    ORDER BY "cnt" ASC  LIMIT 1) 
AS "min_valuable_count" 
FROM "core_author" 

Есть ли способ удалить GROUP BY во внешнем запросе, не удаляя .filter(cnt__gt=3) в подзапросе?

1 Ответ

0 голосов
/ 12 января 2019

Это ошибка, и она будет исправлена ​​в django версии 2.1.6. Вот работа на данный момент:

min_valuable_count_qs = Subquery(
    Book.objects
        .filter(author_name=OuterRef('name'))
        .annotate(cnt=Count('book_category'))
        .filter(cnt__gt=3)
        .order_by('cnt')
        .values('cnt')[:1],
    output_field=models.IntegerField()
)

min_valuable_count_qs.contains_aggregate = False

qs = Author.objects.annotate(min_valuable_count=min_valuable_count_qs))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...