Требуемый SQL будет выглядеть примерно так:
SELECT *
FROM STUDENT
WHERE marks = (SELECT MAX(marks) FROM STUDENT)
Для этого через Django вы можете использовать API агрегации .
max_marks = Student.objects.filter(
subject='Maths'
).aggregate(maxmarks=Max('marks'))['maxmarks']
Student.objects.filter(subject='Maths', marks=max_marks)
К сожалению, на самом деле это два запроса. Выполняется агрегация максимальной отметки, результат выводится в python, а затем передается во второй запрос. (Удивительно), но нет способа передать набор запросов, который является просто агрегацией без группировки, даже если это возможно. Я собираюсь открыть билет, чтобы посмотреть, как это можно исправить.
Edit:
возможно сделать это одним запросом, но это не очень очевидно. Я не видел этот метод в другом месте.
from django.db.models import Value
max_marks = (
Student.objects
.filter(subject='Maths')
.annotate(common=Value(1))
.values('common')
.annotate(max_marks=Max('marks'))
.values('max_marks')
)
Student.objects.filter(subject='Maths', marks=max_marks)
Если вы напечатаете этот запрос в оболочке, вы получите:
SELECT
"scratch_student"."id",
"scratch_student"."name",
"scratch_student"."subject",
"scratch_student"."marks"
FROM "scratch_student"
WHERE (
"scratch_student"."subject" = Maths
AND "scratch_student"."marks" = (
SELECT
MAX(U0."marks") AS "max_marks"
FROM "scratch_student" U0
WHERE U0."subject" = Maths))
Проверено на Django 1.11 (в настоящее время в альфа-версии). Это работает путем группировки аннотации по константе 1, в которую будет сгруппирована каждая строка. Затем мы убираем этот столбец группировки из списка выбора (второй values()
. Джанго (сейчас) знает достаточно, чтобы определить, что группировка избыточна, и устраняет ее. Оставляя один запрос с точным SQL, который нам нужен.