Django Shell индексирование Queryset на любой позиции возвращает точно такой же результат - Ленивая оценка БД
Возможно, это не столько вопрос, сколько утверждение и просьба о более глубоком понимании.
При выполнении запроса QuerySet в оболочке python происходит примерно следующее:
qs = MyModel.objects.all() или qs = MyModel.objects.get_queryset() или qs = MyModel.objects.filter(field='something')
затем следует что-нибудь вроде этого: qs[0] или qs[1] или qs[any_valid_int], то всегда будет возвращаться запись БД в позиции 0 возвращаемого QuerySet, независимо от того, какой индекс вы используете. Сначала это заставило меня почесать голову. Теперь я понимаю, что QuerySets являются генераторами в Django (?) и оцениваются лениво, как описано здесь: Django Doc: Querysets Are Lazy
Когда вы делаете что-либо (в оболочке), что оценивает возвращаемые qs, например len(qs), а затем снова используете индексирование, оно внезапно возвращает правильные записи в БД, а qs[any_valid_int] ведет себя точно так, как ожидалось. Я полагаю, что это соответствует этому вопросу в отчете об ошибке Django от 6 лет назад также.
Итак, на правильном ли я пути, предполагая, что это связано с ленивой оценкой? И каков лучший/быстрый способ в оболочке Django просто получить QuerySet и напрямую проиндексировать тот, который вам нужен для тестирования без необходимости использовать что-то вроде len(qs) сначала? Возможно ли вообще использовать прямое индексирование таким образом, или вам придется итерировать их / фильтровать QuerySet дальше и т.д.? Спасибо
Значит, я на правильном пути, предполагая, что это связано с ленивой оценкой?
Да. Если у вас есть неоцениваемый набор запросов qs, и вы делаете запрос с помощью qs[i], он составит запрос, который будет выглядеть следующим образом:
SELECT … FROM … WHERE … LIMIT 1 OFFSET i
Но если вы не укажете ORDER BY …, то база данных может вернуть записи в любом порядке, и таким образом элемент на позиции 0 в первом запросе, может оказаться на позиции 3 во втором запросе, что может привести к тому, что qs[0] и qs[1] вернут один и тот же элемент.
Если вы используете len(qs), list(qs) или что-либо, что загружает данные в кверисет, то qs[0] будет не делать дополнительный запрос к базе данных: у него уже есть записи в кэше, так что это означает, что он вернет элемент в определенном месте в кэше кверисета, и поскольку записи затем были возвращены в определенном порядке, независимо от того, каков этот порядок, qs[0] и qs[1], таким образом, являются разными записями, возвращенными базой данных.