Как оптимизировать 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)