Получение среднего из средних в 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)