Если я правильно понял из всех комментариев:
В результате получается Articles
( id, path, title ), отфильтрованный по аргументу article
метода get_current_articles
с дополнительными данными - максимум elapsed_time_in_seconds
от всех ArticleStats
каждой отфильтрованной статьи, а также score
ее ArticleStat
с максимумом elapsed_time
.
Если это так, когда базовый запрос может быть включен Article
модель: Article.objects.filter(article=article)
.
Который мы можем аннотировать с помощью Max()
соответствующего ArticleStats
. Это можно сделать непосредственно по основному запросу .annotate(max_date=Max(articlestats__elapsed_time_in_seconds))
или с помощью Подзапрос для ArticleStat
, также отфильтрованный так же, как базовый запрос к статье (мы хотим, чтобы подзапрос выполнялся на том же наборе объектов статьи, что и основной запрос), то есть
max_sq = ArticleStat.objects.filter(
article__article=OuterRef('article')
).annotate(max_date=Max('elapsed_time_in_seconds'))
Теперь, чтобы добавить score
столбец к результату. Max()
является агрегатной функцией и не имеет информации о строке. Чтобы получить score
для максимума elapsed_time
, мы можем сделать еще один подзапрос и отфильтровать его по max elapsed_time
из предыдущего столбца.
Примечание. Этот фильтр может возвращать несколько ArticleStats
объектов для одного и того же максимума elapsed_time
и статья, но мы будем использовать только первый. Ваша структура данных должна убедиться, что фильтр возвращает только одну строку, или обеспечить дополнительную фильтрацию или упорядочение таким образом, чтобы первым был требуемый результат.
score_sq = ArticleStat.objects.filter(
article__article=OuterRef('article'),
elapsed_time_in_seconds=OuterRef('max_date')
)
И использовать наши подзапросы в основном запросе
qset = Article.objects.filter(
article=article
).annotate(
max_date=Max('articlestats__elapsed_time_in_seconds'),
""" or
max_date=Subquery(
max_sq.values('max_date')[:1]
),
"""
score=Subquery(
score_sq.values('score')[:1]
)
).values(
'id', 'path', 'title', 'score', 'max_date'
)
И несколько хитрый вариант без использования функции Max()
, но эмуляция с ORDER BY
и извлечение первого ряда.
artstat_sq = ArticleStat.objects.filter(
article__article=OuterRef('article')
).order_by().order_by('-elapsed_time_in_seconds', '-score')
# empty order_by() to clear any base ordering
qset = Article.objects.filter(
article=article
).annotate(
max_date=Subquery(
artstat_sq.values('elapsed_time_in_seconds')[:1]
),
score=Subquery(
artstat_sq.values('score')[:1]
)
).values(
'id', 'path', 'title', 'score', 'max_date'
)