【问题标题】:Django sql order byDjango sql 排序方式
【发布时间】:2013-04-04 07:35:04
【问题描述】:

我真的在这方面苦苦挣扎。 我需要能够按对用户评论的正面投票数对用户进行排序。

我有一个表格用户配置文件、一个表格评论和一个类似评论的表格。 表评论有一个外键指向它的用户创建者,表 likeComment 有一个外键指向喜欢的评论。 要获得用户收到的正面投票数,我会这样做:

LikeComment.objects.filter(Q(type = 1), Q(comment__user=user)).count()

现在我希望能够按投票最多的用户对所有用户进行排序。我怎么做 ?我尝试使用 extra 和 JOIN 但这并没有去任何地方。

谢谢

【问题讨论】:

    标签: sql database django django-queryset


    【解决方案1】:

    听起来您想对注释执行过滤:

    class User(models.Model):
         pass
    
    class Comment(models.Model):
        user = models.ForeignKey(User, related_name="comments")
    
    class Like(models.Model):
        comment = models.ForeignKey(Comment, related_name="likes")
        type = models.IntegerField()
    
    users = User \
        .objects \
        .all()
        .extra(select = {
            "positive_likes" : """
            SELECT COUNT(*) FROM app_like
            JOIN app_comment on app_like.comment_id = app_comment.id
            WHERE app_comment.user_id = app_user.id AND app_like.type = 1 """})
        .order_by("positive_likes")
    

    【讨论】:

    • 感谢蒂米,我快疯了,可以进行查询了!现在我这样做了,我得到一个 DB 错误:在“SELECT”第 8 行或附近出现语法错误:SELECT COUNT(*) FROM axiom_alto_likecomment
    • 我明白了!这是因为由于某种原因我不能有注释和额外的注释,所以我把所有东西都放进了额外的 ^^ 再次感谢
    【解决方案2】:

    models.py

    class UserProfile(models.Model):
        .........
    
        def like_count(self):
            LikeComment.objects.filter(comment__user=self.user, type=1).count()
    

    views.py

    def getRanking( anObject ):
        return anObject.like_count()
    
    def myview(request):
        users = list(UserProfile.objects.filter())
        users.sort(key=getRanking, reverse=True)       
        return render(request,'page.html',{'users': users})
    

    【讨论】:

    • 这个解决方案是正确的,但是如果站点每分钟获得大量用户或请求,它会产生高负载
    • @Igor 如果你愿意,有很多方法可以减少负载。他可以使用每页加载 10 个用户的分页。他也可以只获取前10或20的用户,其他用户可以搜索。如果你真的想要,问题有很多解决方案。
    • 我一开始是这样做的,但我认为额外的更快^^还是谢谢你,因为你解决了我遇到的另一个问题^^
    【解决方案3】:

    Timmy's suggestion to use a subquery 可能是解决此类问题的最简单方法,但子查询的性能几乎没有连接好,因此如果您有很多用户,您可能会发现您需要更好的性能。

    所以,重用 Timmy 的模型:

    class User(models.Model):
         pass
    
    class Comment(models.Model):
        user = models.ForeignKey(User, related_name="comments")
    
    class Like(models.Model):
        comment = models.ForeignKey(Comment, related_name="likes")
        type = models.IntegerField()
    

    您想要的查询在 SQL 中如下所示:

    SELECT app_user.id, COUNT(app_like.id) AS total_likes
    FROM app_user
    LEFT OUTER JOIN app_comment
                 ON app_user.id = app_comment.user_id
    LEFT OUTER JOIN app_like
                 ON app_comment.id = app_like.comment_id AND app_like.type = 1
    GROUP BY app_user.id
    ORDER BY total_likes DESCENDING
    

    (如果您的实际 User 模型具有的字段不仅仅是 id,那么您需要将它们全部包含在 SELECTGROUP BY 子句中。)

    Django 的对象关系映射系统不提供表达此查询的方法。 (据我所知——如果不是这样,我很高兴被告知!——它只支持跨一个连接的聚合,而不是像这里那样跨两个连接的聚合。)但是当 ORM 不能完全胜任工作时,你总是可以运行raw SQL query,像这样:

    sql = '''
        SELECT app_user.id, COUNT(app_like.id) AS total_likes
        # etc (as above)
    '''
    for user in User.objects.raw(sql):
        print user.id, user.total_likes
    

    【讨论】:

      【解决方案4】:

      我相信这可以通过 Django 的查询集来实现:

      User.objects.filter(comments__likes__type=1)\
          .annotate(lks=Count('comments__likes'))\
          .order_by('-lks')
      

      这里唯一的问题是这个查询会漏掉点赞数为 0 的用户。来自 @gareth-rees、@timmy-omahony 和 @Catherine 的代码也将包括排名为 0 的用户。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-30
        • 2018-09-23
        • 2010-10-19
        • 1970-01-01
        • 2011-12-09
        相关资源
        最近更新 更多