Получить индекс элемента в наборе запросов
У меня есть QuerySet, позвоните ему qs
, который упорядочен некоторым атрибутом, который не имеет отношения к этой проблеме. Тогда у меня есть объект, пусть назовите его obj
. Теперь я хотел бы узнать, какой индекс obj
имеет в qs
, насколько это возможно. Я знаю, что я мог бы использовать .index()
из Python или, возможно, цикл через qs
, сравнивая каждый объект с obj
, но что это лучший способ сделать это? Я ищу высокую производительность и мои единственные критерии.
Использование Python 2.6.2 с Django 1.0.2 в Windows.
Ответы
Ответ 1
QuerySets в Django на самом деле являются генераторами, а не списками (для получения дополнительной информации см. документация Django на QuerySet).
Таким образом, нет ярлыка для получения индекса элемента, и я думаю, что простая итерация - лучший способ сделать это.
Для стартера я бы выполнил ваше требование самым простым способом (например, итерацией); если у вас действительно проблемы с производительностью, тогда я бы использовал другой подход, например, создание запроса с меньшим количеством полей или что-то еще.
В любом случае, идея состоит в том, чтобы оставить такие трюки как можно дольше, когда вы определенно знаете, что они вам нужны.
Обновление: Возможно, вы захотите напрямую использовать некоторый оператор SQL для получения rownumber (что-то ложь. Однако Django ORM не поддерживает это изначально, и вам нужно использовать необработанный SQL-запрос (см. документация). Я думаю, что это может быть лучшим вариантом, но опять же - только если вы действительно видите реальную проблему с производительностью.
Ответ 2
Компактный и, вероятно, самый эффективный:
for index, item in enumerate(your_queryset):
...
Ответ 3
Если вы просто хотите знать, где вы находитесь, среди всех остальных (например, при определении ранга), вы можете сделать это быстро, посчитав объекты перед вами:
index = MyModel.objects.filter(sortField__lt = myObject.sortField).count()
Ответ 4
Предполагая с целью иллюстрации, что ваши модели являются стандартными с первичным ключом id
, затем оценивая
list(qs.values_list('id', flat=True)).index(obj.id)
найдет индекс obj
в qs
. Хотя использование list
оценивает набор запросов, оно оценивает не исходный набор запросов, а производный набор запросов. Эта оценка запускает запрос SQL для получения только полей id, не тратя время на извлечение других полей.
Ответ 5
Вы можете сделать это с помощью queryset.extra(…)
и некоторого необработанного SQL:
queryset = queryset.order_by("id")
record500 = queryset[500]
numbered_qs = queryset.extra(select={
'queryset_row_number': 'ROW_NUMBER() OVER (ORDER BY "id")'
})
from django.db import connection
cursor = connection.cursor()
cursor.execute(
"WITH OrderedQueryset AS (" + str(numbered_qs.query) + ") "
"SELECT queryset_row_number FROM OrderedQueryset WHERE id = %s",
[record500.id]
)
index = cursor.fetchall()[0][0]
index == 501 # because row_number() is 1 indexed not 0 indexed