web-dev-qa-db-fra.com

Récupère l'index d'un élément dans un ensemble de requêtes

J'ai un QuerySet, appelons-le qs, qui est ordonné par un attribut qui n'est pas pertinent pour ce problème. Ensuite, j'ai un objet, appelons-le obj. Maintenant, j'aimerais savoir quel index obj a dans qs, aussi efficacement que possible. Je sais que je pourrais utiliser .index() from Python ou éventuellement parcourir qs en comparant chaque objet à obj, mais quelle est la meilleure comment faire? Je recherche des performances élevées et c'est mon seul critère.

Utilisation de Python 2.6.2 avec Django 1.0.2 sous Windows.

37
Deniz Dogan

Les QuerySets dans Django sont en fait des générateurs, pas des listes (pour plus de détails, voir documentation Django sur QuerySets ).
En tant que tel, il n'y a pas de raccourci pour obtenir l'index d'un élément, et je pense qu'une itération simple est la meilleure façon de le faire.

Pour commencer, je mettrais en œuvre votre exigence de la manière la plus simple possible (comme l'itération); si vous avez vraiment des problèmes de performances, j'utiliserais une approche différente, comme la construction d'un ensemble de requêtes avec une plus petite quantité de champs, ou autre chose.
Dans tous les cas, l'idée est de laisser de telles astuces le plus tard possible, quand vous savez certainement que vous en avez besoin.
Mise à jour: Vous voudrez peut-être utiliser directement une instruction SQL pour obtenir le numéro de commande (quelque chose de mensonger. Cependant, l'ORM de Django ne prend pas en charge cela nativement et vous devez utiliser une requête SQL brute (voir documentation ). Je pense que cela pourrait être la meilleure option, mais encore une fois - seulement si vous voyez vraiment un vrai problème de performances.

16
rob

Compact et probablement le plus efficace:

for index, item in enumerate(your_queryset):
    ...
59
drdaeman

Si vous voulez simplement savoir où se trouve votre objet parmi tous les autres (par exemple lors de la détermination du rang), vous pouvez le faire rapidement en comptant les objets devant vous:

    index = MyModel.objects.filter(sortField__lt = myObject.sortField).count()
34
Richard

En supposant, à des fins d'illustration, que vos modèles sont standard avec une clé primaire id, puis évaluer

list(qs.values_list('id', flat=True)).index(obj.id)

trouvera l'index de obj dans qs. Alors que l'utilisation de list évalue le jeu de requêtes, il n'évalue pas le jeu de requêtes d'origine mais un jeu de requêtes dérivé. Cette évaluation exécute une requête SQL pour obtenir les champs id uniquement, sans perdre de temps à chercher d'autres champs.

13
Vinay Sajip

Vous pouvez le faire en utilisant queryset.extra(…) et du SQL brut comme ceci:

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
2
Jiaaro

Il est possible pour un moyen Pythonic simple d'interroger l'index d'un élément dans un ensemble de requêtes:

(*qs,).index(instance)

Cette réponse décompressera l'ensemble de requêtes dans une liste, puis utilisera la fonction d'index intégrée Python pour déterminer sa position.

2
Peter Brooks