我有一个简单的模型来保持任意数量的基于分数的游戏的分数:
class Score(models.Model):
game = models.ForeignKey(Game, related_name='leaderboards')
value = models.IntegerField(db_index=True)
uom = models.CharField('Unit of Measurement', max_length=10)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
class Meta:
ordering = ['-value']
...
我的Django Rest Framework API视图如下所示,旨在让我获得特定游戏的当前排行榜:
class LeaderboardView(APIView):
...
def get(self, request, pk):
game = get_object_or_404(Game, pk=pk)
# Get all scores order by highest to lowest
scores = (Score.objects.select_related('user').
filter(game=game).
order_by('-value'))
# Create and ordered dict to preserve order added
# and only add user scores who have not been added yet
top10 = collections.OrderedDict()
for obj in scores:
if obj.user.pk not in top10 and len(top10) < 10:
top10[obj.user.pk] = obj
# Turn ordered dict back into a QuerySet list
results = []
for obj in top10.itervalues():
results.append(obj)
serializer = ScoreSerializer(results, many=True)
return Response(serializer.data)
问题是我无法找出如何获得前十名最高分,但将其限制为每个用户一个分数(例如 - 最高分)使用ORM而不是而不是手动获取所有分数然后循环它们以确保我只获得每个用户的最高分。
虽然我可怜地尝试获得我需要的结果,但它必须非常低效,并且必须有更好的方法才能使用ORM的强大功能获得这些结果。
感谢您提前提供任何帮助。
答案 0 :(得分:2)
对from django.db.models.aggregates import Max
leaderboard_data = Score.objects.filter(game=game) \
.values('user') \
.annotate(max_value=Max('value')) \
.order_by('-max_value')
使用注释和聚合。有点像:
GROUP BY
这大致转换为使用Max
运算符的SELECT "user_id", MAX("value") AS "max_value"
FROM "score"
WHERE "game_id" = 1231
GROUP BY "user_id"
ORDER BY "max_value" DESC
查询。
pd.lreshape