Получение среднего из средних в django

У меня есть три таких модели

    class School(models.Model):
      # some fields

    class Class(models.Model):
       school = models.ForeignKey(School, related_name='classes')

    class Student(models.Model):
       class = models.ForeignKey(Class, related_name='students')
       degree = models.IntegerField()

Я хочу упорядочить школы, используя среднюю степень, но средняя степень не является средним значением для всех студентов, так как количество студентов в одном классе не одинаково

поэтому мне нужно получить что-то вроде этого

from django.db.models import Prefetch, Avg
classes = Prefetch('classes', Class.objects.all().annotate(avg_degree=Avg('students__degree'))


# this line would through an error
qs = School.objects.all().prefetch_related(classes)
.annotate(avg_degree=Avg('classes__avg_degree')).order_by('avg_degree')


Конечно, я не могу просто использовать

qs = School.objects.all().annotate(avg_degree=Avg('classes__student__degree'))

это даст неправильные ответы

К сожалению, вы не можете аннотировать столбцы, созданные с помощью другого annotate. Prefetch не предоставляет доступ к полям annotate'd, он используется в основном для фильтрации. Если вам не нужно оперировать этим набором запросов дальше (нужны только значения), вы можете использовать необработанное решение запроса:

from django.db.models import Avg, F

query = (
    Class.objects
    .annotate(avg_degree=Avg('students__degree'), s_id=F('school'))
    .values('s_id', 'deg')
    .query
)
sql, params = query.sql_with_params()
template = '''
SELECT 
    temp.s_id as id, 
    AVG(temp.deg) as degree 
FROM ({}) "temp" 
GROUP BY temp.s_id
'''
qs = School.objects.raw(template.format(sql), params)

# Now we have required field:
for obj in qs:
    print(obj.id, obj.degree)
Вернуться на верх