Django ORM: filter после подзапроса annotate
Этот Джанго-ОРМ запрос:
Model.objects.all() \
.annotate(
ord=Window(
expression=RowNumber(),
partition_by=F('related_id'),
order_by=[F("date_created").desc()]
)
) \
.filter(ord=1) \
.filter(date_created__lte=some_datetime)
Приводит к такому SQL запросу:
SELECT *
FROM (
SELECT
id, related_id, values, date_created
ROW_NUMBER() OVER (
PARTITION BY related_id
ORDER BY date_created DESC
) AS ord
FROM model_table
WHERE date_created <= 2022-02-24 00:00:00+00:00
)
WHERE ord = 1
Фильтр с date_created__lte применяется на внутренний подзапрос. Можно ли как-то вытащить это условие наружу, чтобы оно было вместе/после ord=1?
Есть объект подзапросов Subquery, однако он применяется только в выражениях SELECT и WHERE (методы annotate и filter), а не FROM, в который мне нужно инкапсулировать подзапрос, чтобы применить условие фильтрации на результат подзапроса.
Ответы (1 шт):
Придумал вариант как получит нужные мне данные: применить фильтр, в данном случае date_created__lte, вне запроса с аннотацией.
sub = Model.objects.all() \
.annotate(
ord=Window(
expression=RowNumber(),
partition_by=F('related_id'),
order_by=[F('date_created').desc()]
)
) \
.filter(ord=1)
Model.objects.all() \
.filter(id__in=sub.values_list('id')) \
.filter(date_created__lte=some_datetime)
Однако этот код плох с точки зрения производительности т.к приводит к HASH JOIN. Конечно можно было бы написать чистый SQL запрос и распарсить в Django ORM, но это как-то слишком монструозно для простого подзапроса... В общем, решение получше будет очень кстати ?