我正在尝试使用Django的Window表达式来查找一堆Leaderboard
对象的等级。我需要保存该排名以供以后使用,而这正是造成我麻烦的那部分。
我有一种有效的方法,但是对我来说太慢了。 (是的,我已经设置了@transaction.atomic
)
window = {
'partition_by': [F('category_1'), F('category_2')],
'order_by': F('score').desc()
}
my_filter={"condition_1":True, "condition_2": False}
ranking = Leaderboard.objects.filter(**my_filter).annotate(
r=Window(expression=Rank(), **window)
)
for lb in ranking:
lb.ranking = r
lb.save()
我知道我需要摆脱保存循环并将其替换为update()
调用。因此,我尝试改为这样做:
Leaderboard.objects.filter(**my_filter).update(
ranking=Subquery(
Leaderboard.objects.filter(**my_filter).annotate(
rank=Window(expression=Rank(), **window)
).filter(
pk=OuterRef('pk')
).values('rank')[:1]
)
)
但是当我尝试此操作时,每个Leaderboard
的排名都是1 ...这不是我想要的(但比以前的方法快10倍)。
我认为这是因为我对主键的筛选发生在Window表达式之前,这导致Window表达式在1个对象上运行,而不是在多个对象上运行。要运行update()
,我需要能够将Subquery
的结果降低到个人排名。
我觉得我被Annotations的一些简单属性所绊倒,我只是不知道什么。