Django ORM: создать рейтинг на основе количества связанных моделей - PullRequest
1 голос
/ 20 марта 2019

В моей базе данных есть 2 модели: Movie и Comment (внешний ключ указывает на Movie).

from django.db import models


class Movie(models.Model):
    title = models.CharField(max_length=120, blank=False, unique=True)

class Comment(models.Model):
    movie = models.ForeignKey(movie_models.Movie, null=False, on_delete=models.CASCADE)
    body = models.TextField(blank=True)

Что я пытаюсь сделать, это создать рейтинг Movies, где позиция определяется числом связанных Comments.

. Я могу комментировать количество комментариев иправильно упорядочить результат:

from django.db.models import Count

qs = Movie.objects.annotate(total_comments=Count('comment')).order_by('-total_comments')

Это дает мне набор запросов в правильном порядке, но я хотел бы сделать еще одну вещь - аннотировать 'rank' для каждой строки.

Так что мой вопрос: как я могу пометить «ранг» для каждой строки результата?Обратите внимание, что для фильмов с одинаковым количеством комментариев требуется одинаковый ранг.

|  movie_title | total_comments | rank |
|--------------|----------------|------|
| mov1         | 10             | 1    |
| mov2         | 5              | 2    |
| mov3         | 5              | 2    |
| mov4         | 3              | 3    |

Я пытался использовать оконные функции , так как некоторые примеры показались мне законными:

from django.db.models import F, Window

dense_rank = Window(
    expression=DenseRank(),
    order_by=F('total_comments').desc()
)

qs = Movie.objects.annotate(total_comments=Count('comment')).annotate(rank=dense_rank)

Но выполнение этого запроса повышает django.db.utils.OperationalError: near "(": syntax error

1 Ответ

2 голосов
/ 20 марта 2019

RowNumber должно быть достаточно, если запрос правильно упорядочен:

from django.db.models import Count
from django.db.models.expressions import F, Window
from django.db.models.functions.window import RowNumber

qs = (Movie.objects
    .annotate(total_comments=Count('comment'))
    .order_by('total_comments')
    .annotate(rank = Window(expression=RowNumber())
)

Но так как номер строки присущ последовательности записей, Кевин прав, предлагая простой метод Python (например,enumerate) поскольку вы все равно будете итерировать набор записей в какой-то момент.

Было бы иначе, если бы вы хотели, чтобы порядок записей для вашего набора отличался от ранжирования, тогда было бы целесообразноиспользуйте Window с отдельным параметром order_by.

Я не уверен, поддерживается ли RowNumber всеми бэкэндами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...