如何在Django中按计算值排序

7

嘿,我想在Django中根据计算值对对象进行排序...我该怎么做?

以下是一个基于Stack Overflow的用户配置文件模型示例,解释了我的困境:

class Profile(models.Model):
    user = models.ForeignKey(User)

    def get_reputation():
        ... 
        return reputation
    reputation = property(get_reputation)

那么,假设我想通过声望来对用户进行排序。我该怎么做呢?我知道你不能仅仅这样做:

Profile.objects.order_by("-reputation")

感谢大家的帮助:)
3个回答

16

由于你的计算代码仅存在于Python中,因此你必须在Python中进行排序:

sorted (Profile.objects.all (), key = lambda p: p.reputation)

嘿,这是我所问问题的答案,但我接受了其他人的答案,因为它解决了我的问题...特别是S.Lott的评论。不过我还是点赞了你的回答 :) - Jiaaro
有什么方法可以将其返回查询集而不是常规的Python列表(或将列表转换为查询集)吗? - Jiaaro
这似乎在评论中要求有点过于繁重,所以我将其移动到了自己的问题中:https://dev59.com/PHNA5IYBdhLWcg3wL6yx - Jiaaro

7
截至Django-1.8,只要计算值可以在SQL中呈现,就可以使用查询表达式对QuerySet进行排序。您还可以将注释添加到模型中,作为order_by项。
from django.db.models import F
Profile.objects.annotate(reputation=(F('<field>') + ...)).order_by("-reputation")

基本操作,如+-*/**可以与F()一起使用。此外,还有几个其他函数,例如CountAvgMax等。
链接: 另请参阅此SO问答:通过聚合字段值对QuerySet进行排序

4

如果您需要在数据库中进行排序(因为您有大量记录,需要对其进行分页等操作),唯一的真正选择是将声誉转化为非规范化字段(例如,在模型上重写save()方法中更新)。


我决定使用post-save信号而不是覆盖save()函数...这种方法是否存在任何潜在的问题? - Jiaaro
如果你想使用信号,我建议使用pre_save而不是post_save。使用post_save来保持一个非规范化字段的最新状态意味着你必须执行两个UPDATE查询,而只需要一个就足够了。 - Carl Meyer
@Carl Meyer 感谢你,我实际上正在更新一个不同于正在保存的模型,但还是谢谢你。我认为经验法则是,如果要更新与正在保存的模型不同的模型,则使用 post-save,如果要更新相同的模型,则使用 pre-save,对吗? - Jiaaro
@Jim Robert 当然,这种情况下你需要使用post_save来确保只有在模型成功保存时才进行更新。 - Carl Meyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接