Я пытаюсь использовать выражения окна Джанго, чтобы найти ранг группы 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
результаты были доведены до ранга отдельного человека.
Мне кажется, что меня запутало какое-то простое свойство аннотаций, япросто не знаю что.