Как оптимизировать 2 annotate
2 annotate создают большую нагрузку на БД: вот почему.
Перед прочтением лучше узнать о ленивых запросах.
Но и доставать кол-во комментариев для постов по одному запросу всё ещё жутко не эффективно. Можно оптимизировать это так:
1. Достать id самых популярных постов (annotate по лайкам)
most_popular_posts = Post.objects.annotate(likes_count=Count('likes')).order_by('-likes_count')
most_popular_posts_ids = [post.id for post in most_popular_posts]
2. Достать количество комментариев для этих постов с помощью annotate (annotate по комментариям
posts_with_comments = Post.objects.filter(id__in=most_popular_posts_ids).annotate(comments_count=Count('comments'))
ids_and_comments = posts_with_comments.values_list('id', 'comments_count')
count_for_id = dict(ids_and_comments)
ids_and_comments — это список пар из id и количества комментариев. Выглядит так: <QuerySet [(165, 138), (244, 138), (95, 143), (444, 112), (368, 126)]>. С помощью dict() он преобразуется в обычный словарь, где ключ — это id поста, а значение — количество комментариев.
3. Присоединить количество комментариев к постам (Объединение)
for post in most_popular_posts:
post.comments_count = count_for_id[post.id]
У поста нет такого поля, но вы можете вот так “временно” их добавлять. Это происходит только на уровне Python, в БД ничего не меняется.
4. Как пользоваться
Теперь у поста есть оба атрибута:
for post in most_popular_posts:
print(post.likes_count)
print(post.comments_count)