Ответ 1
Требуемый 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()
). Django (сейчас) знает достаточно, чтобы определить, что группировка избыточна и исключает ее. Оставляя единственный запрос с точным SQL, который нам нужен.