11
votes

Comment puis-je obtenir la position d'un résultat dans la liste après un ordre_by?

J'essaie de trouver un moyen efficace de trouver le rang d'un objet dans la base de données liée à son score. Ma solution naïve ressemble à ceci:

rank = 0
for q in Model.objects.all().order_by('score'):
  if q.name == 'searching_for_this'
    return rank
  rank += 1


1 commentaires

Quelque chose comme: 1. Sélectionnez Score comme récupéré_score où nom = 'Recherche_for_this' 2. Sélectionnez Compte (*) où score -> Classement


4 Réponses :


2
votes

dans "RAW SQL" avec un moteur de base de données conformément à la normale (PostgreSQL, SQL Server, Oracle, DB2, ...), vous pouvez simplement utiliser la fonction SQL-Standard Rank - mais Ce n'est pas pris en charge dans des moteurs populaires mais non standard tels que MySQL et SQLite, et (peut-être à cause de cela) Django ne "surface" ne "surface" ne "pas" cette fonctionnalité à l'application.


2 commentaires

Ah, je teste sur SQLite avant le déploiement vers PGSQL.


@Bobbob, si vous le souhaitez, vous pouvez exécuter une petite instance locale de PostgreSQL à des fins de test - ce n'est ni dur ni onéreux.



2
votes

Utilisez quelque chose comme ceci: xxx

Vous pouvez pré-calculer les rangs et le sauvegarder sur le modèle si elles sont fréquemment utilisées et affectent les performances.


0 commentaires

16
votes

Je ne pense pas que vous puissiez le faire dans une interrogation de la base de données à l'aide de Django Orm. Mais si cela ne vous dérange pas, je créerais une méthode personnalisée sur un modèle: xxx pré>

Vous pouvez ensuite utiliser "classement" n'importe où, comme s'il s'agissait d'un champ normal: P >

print Model.objects.get(pk=1).ranking


4 commentaires

Merci, c'est exactement ce que je cherchais.


Merci. Notez que dans l'exemple que vous avez donné, l'ordre était ascendant (en d'autres termes "plus le score inférieur, plus le classement"), donc je suis allé avec elle. Si le score plus élevé devrait effectivement augmenter le classement, vous devez modifier «Score__LT» sur «Score__GT».


Cela devrait être calculé en calcul, car il exécutera la requête globale de classement pour chaque ligne dans Model.ObjectS.all ()


@mehmet oui, bien sûr. C'est ce que j'essayais de dire au premier paragraphe de ce post. À l'époque (il y a 6 ans), il n'y avait pas de moyen plus efficace de le faire en utilisant django orm. De nos jours, il pourrait y avoir une solution PostgreSQL uniquement à l'aide des fonctions de fenêtre PostgreSQL et une fonction d'annotation personnalisée. Je pourrais regarder cela quand j'ai plus de temps.



11
votes

3 commentaires

C'est génial, mon seul problème est quand je fais plus de filtrage après le query, il ne contient pas le rang. Comme si je reçois tous les résultats les classant, puis filtrant par nom d'utilisateur Le résultat est classé par rapport à ce query plus petit, pas le tout.


Comment ai-je résolu ce n'est peut-être pas la meilleure solution, c'est que j'ai créé un dictionnaire d'assistant d'une requête globale, pour l'ID utilisateur et le rang, et pour afficher le rang réel, j'utilise le dictionnaire d'assistant ajoutant plutôt le grade au requérant filtré.


travaille-t-il sur la version de MySQL 5.7 Aurora? Une idée