Как аннотировать модель select_related? - PullRequest
2 голосов
/ 04 мая 2019

Я выбрал связанный объект для каждого объекта в моем наборе запросов. Как я могу аннотировать вычисленное значение для каждого?

Модель:

class School(models.Model):
    name = models.CharField(max_length=255)


class Teacher(models.Model):
    name = models.CharField(max_length=255)
    school = models.ForeignKey(School)


class Student(Entity):
    name = models.CharField(max_length=255)
    school = models.ForeignKey(School)

Я хочу собрать всех учителей и для каждого из них свою школу и количество учеников в этой школе.

Вот что я попробовал:

teachers = Teacher.objects.select_related('school').annotate(student_count=Count('school__student'))

Но я вижу, что это неправильно, так как количество учеников должно быть на школу .

Я ожидаю, что потом смогу сделать что-то подобное с моим набором запросов:

for teacher in teachers:
  print(teacher.name, teacher.school.name, teacher.school.student_count)

1 Ответ

0 голосов
/ 04 мая 2019

Но я вижу, что это неправильно, поскольку количество учеников должно быть на школу .

Ну, вы будете считать учеников, которые принадлежат к школек которому принадлежит этот учитель, так что это семантически верно.Однако аннотация будет помещена на объекты в наборе запросов, следовательно, на учителя, поэтому вы можете получить количество учеников с помощью:

for teacher in teachers:
  print(teacher.name, teacher.school.name, <b>teacher.student_count</b>)

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

Вы можете решить использовать .prefetch_related(..) для данного school и аннотировать этот набор запросов в Prefetch object [Django-doc] , это приведет к дополнительным запросам, но менее дорогим.Например:

from django.db.models import Prefetch, Count

teachers = Teacher.objects.prefetch_related(
    Prefetch(
        'school',
        queryset=School.objects.annotate(<b>student_count=Count('student')</b>)
    )
)

Тогда вы действительно можете запросить с помощью:

for teacher in teachers:
  print(teacher.name, teacher.school.name, <b>teacher.school.student_count</b>)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...