Как мне получить позицию результата в списке после order_by? - PullRequest
6 голосов
/ 17 апреля 2010

Я пытаюсь найти эффективный способ найти ранг объекта в базе данных, связанный с его оценкой.Мое наивное решение выглядит так:

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

Должна быть возможность заставить базу данных выполнять фильтрацию, используя order_by:

Model.objects.all (). Order_by ('score') .filter (name =' search_for_this ')

Но, похоже, нет способа извлечь индекс для шага order_by после фильтра.

Есть ли лучший способсделать это?(Использование python / django и / или необработанного SQL.)

Моя следующая мысль - предварительно вычислить ранги при вставке, но это выглядит грязно.

Ответы [ 4 ]

8 голосов
/ 17 апреля 2010

Я не думаю, что вы можете сделать это в одном запросе к базе данных, используя Django ORM. Но если вас это не беспокоит, я бы создал собственный метод для модели:

from django.db.models import Count

class Model(models.Model):
    score = models.IntegerField()
    ...

    def ranking(self):
        aggregate = Model.objects.filter(score__lt=self.score).aggregate(ranking=Count('score'))
        return aggregate['ranking'] + 1

Затем вы можете использовать «рейтинг» в любом месте, как если бы это было обычное поле:

print Model.objects.get(pk=1).ranking
3 голосов
/ 13 июля 2018

Используя новые функции Window в Django 2.0 , вы можете написать это так ...

from django.db.models import Sum, F
from django.db.models.expressions import Window
from django.db.models.functions import Rank

Model.objects.filter(name='searching_for_this').annotate(
            rank=Window(
                expression=Rank(),
                order_by=F('score').desc()
            ),
        )
2 голосов
/ 17 апреля 2010

В «сыром SQL» со стандартным ядром базы данных (PostgreSql, SQL Server, Oracle, DB2, ...) вы можете просто использовать стандартную функцию SQL RANK - но это не поддерживается в популярных но нестандартные движки, такие как MySql и Sqlite, и (возможно, из-за этого) Django не «прикрывают» эту функциональность для приложения.

1 голос
/ 17 апреля 2010

Используйте что-то вроде этого:

obj = Model.objects.get(name='searching_for_this')
rank = Model.objects.filter(score__gt=obj.score).count()

Вы можете предварительно вычислить ранги и сохранить их в модели, если они часто используются и влияют на производительность.

...