Django комментирует функцию, которая возвращает максимум поля среди всех объектов, имеющих функцию

Предположим, что у меня есть эта модель:

class Student(models.Model):
    class_name = models.CharField()
    mark = models.IntegerField()

И я хочу, чтобы все студенты, которые имеют самые высокие mark в своем классе. Я могу получить студента, который имеет самый высокий mark во всех классах, как это упоминается в этом посте. Но я хочу, чтобы все студенты, которые имеют самый высокий mark в своем классе примерно так:

Student.objects.annotate(
    highest_mark_in_class=Max(
        Students.objects.filter(class_name=F('class_name'))
        .filter(mark=highest_mark_in_class)
    )
)

Я могу сделать это с for цикл, но с большой базой данных for петли довольно медленные. Я не знаю, возможно ли написать такой запрос в одну строку?

1 ответ

Для этого вам нужно будет использовать 2 запроса:

import operator
from functools import reduce
from django.db.models import Max, Q

best_marks = Student.objects.values('class_name').annotate(mark=Max('mark'))
q_object = reduce(operator.or_, (Q(**x) for x in best_marks))
queryset = Student.objects.filter(q_object)

Первый запрос получает список лучших оценок для каждого класса.

Второй запрос получает всех учащихся, где отметка и класс соответствуют одному элементу списка.

Обратите внимание, что если вы звоните .annotate(best_mark=Max('mark')) вместо .annotate(mark=Max('mark')), вам придется проделать дополнительную работу, чтобы переименовать best_mark как mark до передачи словаря в Q объект. В то время как Q(**x) это довольно удобно.

Другие вопросы по тегам