Оптимизация производительности запросов в Django

Я создаю сайт блога на django и при создании страницы для определенных записей блога я столкнулся с проблемой запроса данных с помощью ORM.

У меня есть модель Post, которая связана с другой моделью comments, где фиксируются все комментарии. Модель комментариев имеет следующие поля ->

class Comment(models.Model):
    comment = models.TextField(null=True)
    Created_date = models.DateTimeField(auto_now_add=True)
    Updated_date = models.DateTimeField(auto_now=True)
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments_post')
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='comments_user')

    def __str__(self):
        return self.comment

Теперь при запросе одной записи блога может быть N количество комментариев и для каждого комментария назначен пользователь, который написал комментарий. Поэтому я хочу найти данные пользователя (имя, email или номер телефона) для каждого комментария.

Запрос, который я выполнил, ->

post = Post.objects.select_related().prefetch_related('images_set','comments_post').get(id=post_id)

Теперь, когда я пытаюсь использовать {{post.user.email}} и если есть 3 комментария к посту, ORM будет запрашивать 3 раза к БД, чтобы найти email для каждого пользователя. Но если я использую {{post.user_id}}, то запрос будет сделан только один раз, так как он предварительно загружает user_id, так как он доступен в таблице комментариев.

Есть ли способ сделать только один запрос к БД, чтобы получить все имена для всех комментариев?

Возможно prefetch_related внешний ключ внутри внешнего ключа. Например, prefetch_related('comments_post__user'), или если вам нужна большая производительность, вы можете использовать annotate. Аннотируйте обязательное поле, это быстрее, чем prefetch

Вы можете сохранить дополнительный запрос к базе данных, который извлекает пользователя с помощью объекта Prefetch [Django-doc]:

from django.db.models import Prefetch

post = Post.objects.select_related().prefetch_related(
    'images_set',
    Prefetch('comments_post', Comment.objects.select_related('user'))
).get(id=post_id)

Это сделает три обхода к базе данных: один для Post, один для image_set и один для comments_post. В последнем случае также будут получены данные пользователя, чтобы не делать дополнительный запрос для этого.

Вернуться на верх