我的数据库中有 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')
这为我提供了正确顺序的查询集,但我还想做一件事 - 为每一行注释“排名”。
所以我的问题是:如何为结果的每一行注释“排名”?请注意,评论数量相同的电影必须具有相同的排名。
| movie_title | total_comments | rank |
|--------------|----------------|------|
| mov1 | 10 | 1 |
| mov2 | 5 | 2 |
| mov3 | 5 | 2 |
| mov4 | 3 | 3 |
我尝试使用 window functions ,因为有些例子对我来说似乎是合法的:
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
最佳答案
如果查询顺序适当,
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())
)
但由于行号是记录序列中固有的,Kevin 正确地建议了一种简单的 Python 方法(例如 enumerate
),因为您将在某些时候迭代记录集无论如何点。
如果您希望记录集的排序与排名的排序不同,那么将 Window
与单独的 order_by
参数一起使用是有意义的。
我不确定 RowNumber
是否被所有后端支持。
关于 Django ORM : create ranking based on related model count,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55260238/