Предположим, я хочу показать список бегунов, упорядоченных по их последнему времени спринта.Django: заказ QuerySet на основе последнего детского модельного поля
class Runner(models.Model):
name = models.CharField(max_length=255)
class Sprint(models.Model):
runner = models.ForeignKey(Runner)
time = models.PositiveIntegerField()
created = models.DateTimeField(auto_now_add=True)
Это быстрый эскиз того, что я хотел бы сделать в SQL:
SELECT runner.id, runner.name, sprint.time
FROM runner
LEFT JOIN sprint ON (sprint.runner_id = runner.id)
WHERE
sprint.id = (
SELECT sprint_inner.id
FROM sprint as sprint_inner
WHERE sprint_inner.runner_id = runner.id
ORDER BY sprint_inner.created DESC
LIMIT 1
)
OR sprint.id = NULL
ORDER BY sprint.time ASC
В Django QuerySet documentation состояний:
Допустимо указывать многозначное поле на заказ результаты (например, поле ManyToManyField). Обычно это не будет то, что нужно делать, и это действительно расширенная функция использования. Однако, если вы знаете, что фильтрация вашего запроса или доступные данные подразумевает, что для каждого из будет отображаться только один элемент данных заказа, то вы можете точно указать то, что вы хотите сделать. Используйте упорядочение по многозначным полям с осторожностью и убедитесь, что результаты ожидаются.
Я думаю, мне нужно применить некоторый фильтр здесь, но я не уверен, что именно Джанго ожидает ...
Одно примечание, потому что это не очевидно, в этом примере: таблица Runner будет иметь несколько сто записей, спринты также будут иметь несколько сотен, а через несколько дней, вероятно, несколько тысяч записей. Данные будут отображаться в разбитом на страницы, поэтому сортировка в Python не является вариантом.
Единственная другая возможность, которую я вижу, это написать SQL сам, но я бы хотел избежать этого любой ценой.
Не связано ли это относительно высокое использование памяти? Насколько я могу судить, он забирает по крайней мере каждого бегуна в память и строит довольно большой список своих идентификаторов спринта. Выполнение этого на каждом просмотре страницы с несколькими сотнями участников в БД заставляет меня чувствовать себя * немного неудобно. Наверное, это кеширование. – Strayer
После тестирования этого с 10 000 бегунов он использовал менее 10 МБ (3 МБ на самом деле ...) ОЗУ. Если вы думаете, что вам понадобится больше, вам действительно нужно использовать raw SQL. Как всегда, лучший подход к этому - сначала профиль, а не спекуляция. Преждевременная оптимизация и все это ... – Matt
И несколько сотен записей действительно не много ... конечно, недостаточно, чтобы не беспокоиться о оптимизации производительности. Несколько сотен тысяч записей, как правило, там, где вы начнете думать об этом, и даже тогда это обычно не большая проблема (бросать в индекс или два, и он разрешен). – Matt