Django — использование prefetch_related

#django #django-models

#django #django-модели

Вопрос:

независимо от того, сколько руководств / документации я прочитал, я все еще не совсем понимаю, как именно я должен использовать prefetch_related.

Мой models.py:

 class ProfileComment(models.Model):
    author       = models.ForeignKey('Profile', on_delete=models.CASCADE, null=True)
    date_posted  = models.DateTimeField(default=timezone.now, editable=False)
    body         = models.CharField(max_length=180, blank=True)
    ...

class Profile(models.Model):
    user     = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    comments = models.ManyToManyField(ProfileComment, related_name='comments', blank=True)
    avatar   = models.FileField(upload_to=avatar_folder, default='user-avatar/default.png')
    ...
 

Мой views.py:

 profile = Profile.objects.prefetch_related('comments').get(user=request.user)
 

И в шаблоне:

 {% for comment in profile.comments.all %}
<div>
  <p>Author: {{ comment.author.user }}</p><img src="{{ comment.author.avatar.url }}">
  <p>Message: {{ comment.body }}</p>
  <p>Date posted: {{ comment.date_posted }}</p>
</div>
{% endfor %}
 

Однако, независимо от того, что я добавляю в prefetch_related, количество запросов просто увеличивается примерно на 5 для каждой записи

Комментарии:

1. Prefetch_related создаст дополнительные запросы. Для а .get(user=request.user) это вообще не будет иметь никакого значения.

2. Итак, как я могу сделать так, чтобы он не делал еще 10 запросов для 1 записи?

3. В настоящее время у меня есть 10 записей, и для их загрузки требуется 80 запросов

4. вы этого не делаете. .prefetch_related выполняет дополнительные запросы для минимизации пропускной способности к базе данных. Если вы хотите получить все комментарии в одном запросе, вы повторяете данные для профиля в каждой записи . Если вы сделаете это для дополнительного отношения, вы повторяете данные профиля, умноженные на количество строк, а данные комментария умножаются на другое отношение.

5. это из-за comment.author.user части. Это можно оптимизировать с .select_related помощью .

Ответ №1:

.prefetch_related(…) [Django-doc] следует использовать для массовой выборки связанных объектов для набора запросов. Поскольку вы пишете:

 ….get(user=request.user) 

однако это не будет иметь никакого значения, поскольку вы извлекаете только один объект, и, таким образом, он будет предварительно выбирать комментарии в дополнительном запросе.

Однако что вы можете свести к минимуму , так это количество дополнительных запросов , которые исходят от comment.author.user вас . Это приведет к двум дополнительным запросам для каждого комментария, так ForeignKey как они загружаются лениво.

Таким образом, ваш вид может выглядеть следующим образом:

 profile = Profile.objects.get(user=request.user)
comments = profile.comments.select_related('author', 'author__user') 

где вы передаете оба profile и comments в шаблон, а затем извлекаете его с помощью:

 {% for comment in comments %}
<div>
  <p>Author: {{ comment.author.user }}</p><img src="{{ comment.author.avatar.url }}">
  <p>Message: {{ comment.body }}</p>
  <p>Date posted: {{ comment.date_posted }}</p>
</div>
{% endfor %} 

таким образом, здесь мы читаем комментарии из набора запросов, в котором мы извлекаем профиль и пользователя этого профиля в одном запросе. В результате мы сделаем два запроса: один для Profile , и один для всех Comment s , включая .author и .author.user .

Комментарии:

1. спасибо, это действительно помогло с путаницей