Django дублирует запросы к базе данных - PullRequest
2 голосов
/ 03 ноября 2019

Я использую django_debug_toolbar для анализа производительности веб-страницы. Что смущает меня в результатах - это запросы к базе данных. Независимо от того, что я сделал все как положено (я полагаю), на вкладке результатов все равно отображается предупреждение о дублировании запросов к базе данных. Чтобы проиллюстрировать эту проблему, я изложил проект django следующим образом:

models.py

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published', auto_now_add=True)


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

views.py

from django.shortcuts import render

from .models import Question, Choice


def index(request):
    return render(request, 'polls/index.html', {'questions': Question.objects.all()})

index.html

{% for question in questions %}
  <p>{{ question.question_text }}</p>
  <ul>
    {% for choice in question.choice_set.all %}
      <li>{{ choice.votes }} votes - {{ choice.choice_text }}</li>
    {% endfor %}
  </ul>
{% endfor %}

В приведенном выше html-файле и представлении я загружаю все вопросы и связанные с ними варианты. Для тестирования я добавил только 2 вопроса и 2 и 4 варианта для них соответственно (всего 6 вариантов). И django_debug_toolbar Результат SQL приведен ниже:

enter image description here

enter image description here

Что делатьчтобы избежать этих дублирующих SQL-запросов? Я думаю, что этот дублированный запрос может серьезно повлиять на производительность больших веб-сайтов. Каков ваш подход и лучшие практики, чтобы избежать этих проблем в целом?

1 Ответ

3 голосов
/ 03 ноября 2019

Вы должны .prefetch_related(..) [Django-doc] связанных Choice с. Затем Django сделает дополнительный запрос, чтобы получить Choice s одновременно, и выполнит JOIN на уровне Python / Django.

def index(request):
    return render(
        request,
        'polls/index.html',
        {'questions': Question.objects.<b>prefetch_related('choice_set')</b>}
    )
...