Django оптимизирует запросы с помощью циклов - PullRequest
2 голосов
/ 28 февраля 2011

Можно ли оптимизировать Django, чтобы он не выполнял так много запросов на что-то вроде этого

for student in Student.objects.all():
    for course in student.course_set.all():
        for grade in course.grade_set.filter(student=student):
            # do stuff

Количество запросов - это оценки студентов * курсов *, которые могут быть огромными.edit Одна возможность после получения некоторых идей из блога Roseman.

for grade in student.grade_set.order_by('course', 'marking_period').select_related():
    if grade.marking_period_id in some_report_input:
        # do stuff

Это всего лишь фрагмент, но в основном я заменил циклы for на один цикл for для последнего элемента, который меня волнует (оценки).все, что мне нужно (студент, курс, период сдачи экзаменов).Ключевым было использование таких вещей, как mark_period_id вместо grade.marking_period (который выполняет другой запрос).

Компромисс - читаемость кода.Я хотел отфильтровать оценки и организовать на основе критериев.Это идет от тривиального к запутанному.

Это ни в коем случае не общее решение.Я уверен, что бывают случаи, когда это совсем не поможет.Пожалуйста, прокомментируйте, если вы знаете лучший способ.

Другой пример:

for student in students:
  print student
  for department in departments:
    print department
    failed_grades = Grade.objects.filter(course__department=department,course__courseenrollment__user=student,grade__lte=70)
      for failed_grade in failed_grades:
        print grade.course
        print grade.grade

Студент записывается на курс.У курса есть отдел.

Ответы [ 2 ]

1 голос
/ 04 июня 2012

Было бы полезно, если вы опубликуете код вашей модели и код "делать вещи", который вы пропустили. Таким образом, мы могли бы понять, как сделать эффективный запрос в вашем случае.

Тем не менее, я думаю это может быть полезным. Он охватывает некоторые случаи, которых select_related нет. Обратите внимание, что prefetch_related доступно начиная с Django 1.4 , поэтому вам может потребоваться обновление до этой версии, чтобы использовать его.

Для нас очень важно помочь вам добавить сюда свой код "делать вещи", и, если он уместен (и я думаю, что это будет), добавить сюда код вашей модели (только объявления полей будут в порядке). Потому что способ получения оптимизированного запроса зависит от того, как связаны ваши модели и как вы используете результаты набора запросов.

EDIT:

Чтобы оптимизировать последнее «для» вашего последнего примера, вы можете сделать это:

failed_grades = Grade.objects.filter(course__department=department,course__courseenrollment__user=student,grade__lte=70).select_related('course')
for failed_grade in failed_grades:
    print grade.course
    print grade.grade

В этом примере, когда вы делаете grade.course, часть select_related этого запроса кэширует все курсы, связанные с отфильтрованными оценками, поэтому вы можете использовать их, выполняя только один запрос. Таким образом, если метод __unicode__ модели курса использует только свои собственные поля (я имею в виду, если вы не показываете какие-либо другие данные модели в методе unicode курса), вы должны получить более высокую производительность (меньше запросов) ) что в вашем примере. Я не уверен, как улучшить других для заявлений, как вы хотите. Но я думаю, что это может помочь вам получить то, что вы хотите (возможно, я не слишком разбираюсь в ваших моделях, чтобы помочь вам лучше)

0 голосов
/ 28 февраля 2011

вы можете использовать select_related (), и он попадет в базу данных только один раз.

Дополнительная информация по этой ссылке (документация Django) http://docs.djangoproject.com/en/1.2/ref/models/querysets/#select-related

Пример того, как вы могли бы использовать это в вашем случае

for x in Student.objects.select_related():
    do stuff with x.course.grade`
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...