如何根据查询集中的值为对象分配排名
Posted
技术标签:
【中文标题】如何根据查询集中的值为对象分配排名【英文标题】:How to assign ranking on objects based on a value in a queryset 【发布时间】:2021-08-21 07:24:50 【问题描述】:我有一个查询集,它返回一个菜单列表,我想根据累积的票数为每个菜单分配一个排名有没有一种方法可以使用 django 查询表达式来实现这一点?我也愿意接受任何其他建议。
查询集如下:
qs = Menu.objects.filter(Q(created_at__date__iexact=todays_date)).order_by('-votes')
Menu类模型如下图所示:
class Menu(models.Model):
"""Represents menu class model"""
restaurant = models.ForeignKey(Restaurant,null=True,blank=True,on_delete=models.CASCADE)
file = models.FileField(upload_to='menus/')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
uploaded_by = models.CharField(max_length=50, null=True, blank=True)
votes = models.IntegerField(default=0)
查询集序列化后返回如下数据:
[
"id": 10,
"file": "https://res.cloudinary.com/dw9bllelz/raw/upload/v1/media/menus/index_ah660c.jpeg",
"restaurant": "Burger King",
"votes": 10,
"created_at": "2021-06-03T09:33:05.505482+03:00"
,
"id": 9,
"file": "https://res.cloudinary.com/dw9bllelz/raw/upload/v1/media/menus/index_ah660c.jpeg",
"restaurant": "Texas Plates",
"votes": 2,
"created_at": "2021-06-03T09:33:05.505482+03:00"
,
"id": 8,
"file": "https://res.cloudinary.com/dw9bllelz/raw/upload/v1/media/menus/index_ah660c.jpeg",
"restaurant": "Carlito Dishes",
"votes": 2,
"created_at": "2021-06-03T09:33:05.505482+03:00"
,
"id": 7,
"file": "https://res.cloudinary.com/dw9bllelz/raw/upload/v1/media/menus/index_ah660c.jpeg",
"restaurant": "Kram Dishes",
"votes": 1,
"created_at": "2021-06-03T09:33:05.505482+03:00"
,
]
【问题讨论】:
@AbdulAzizBarkat 更新了问题。 你已经有了order_by('-votes')
,那么数组中项目的索引(或者更准确地说是index + 1
)不是它的排名吗?
@AbdulAzizBarkat 我明白你的意思了
如果您愿意,您也可以使用Window functions (Django docs) 并根据您的需要使用Rank
或DenseRank
(Reference)。
你在使用 django rest 框架吗?
【参考方案1】:
您可以使用数组中对象的 index 作为其索引,也可以使用Window
functions [Django docs] 并使用Rank
或DenseRank
(Reference [Django docs]) 函数来计算根据您的需要排名:
from django.db.models import F, Window
from django.db.models.functions import Rank
qs = Menu.objects.filter(
Q(created_at__date__iexact=todays_date)
).annotate(
rank=Window(
expression=Rank(),
order_by=F('votes').desc(),
)
)
for menu in qs:
print(menu.rank, menu.votes)
【讨论】:
它只返回过滤后的查询集我看不到排名:[<Menu: Burger King 3 VOTES>, <Menu: Westeros Munchies 1 VOTES>, <Menu: Burger King 1 VOTES>, <Menu: Burger King 1 VOTES>, <Menu: Pizza King 0 VOTES>]
@PhilipMutua 为什么会在查询集字符串表示中显示排名?这会调用模型的__str__
来生成这些表示。检查我的编辑模型实例是否得到了排名注释。
对qs
查询集应用过滤器后如何保持原来的排名?以上是关于如何根据查询集中的值为对象分配排名的主要内容,如果未能解决你的问题,请参考以下文章
如何根据 Kendo Grid Angular 4 中的条件为一列分配 2 个字段