【问题标题】:Django query aggregate upvotes in backward relationDjango查询聚合后向关系的赞成票
【发布时间】:2013-10-18 16:44:19
【问题描述】:

我有两个模型:

Base_Activity:
    some fields

User_Activity:
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    activity = models.ForeignKey(Base_Activity)
    rating = models.IntegerField(default=0) #Will be -1, 0, or 1

现在我想查询 Base_Activity,并排序具有最对应用户活动且评分=1 的项目。我想做类似下面的查询,但=1 部分显然不起作用。

activities = Base_Activity.objects.all().annotate(
    up_votes = Count('user_activity__rating'=1),
).order_by(
    'up_votes'
)

我该如何解决这个问题?

【问题讨论】:

    标签: django django-models django-queryset


    【解决方案1】:

    你不能像错误消息所说的那样使用Count

    语法错误:关键字不能是表达式

    Count 的参数必须是一个简单的字符串,比如user_activity__rating

    我认为将AvgCount 一起使用是一个不错的选择:

    activities = Base_Activity.objects.all().annotate(
        a=Avg('user_activity__rating'), c=Count('user_activity__rating')
    ).order_by(
        '-a', '-c'
    )
    

    rating=1 活动最多的项目的平均值应该最高,在具有相同平均值的用户中,活动最多的用户会排名靠前。

    如果您想排除有否决票的项目,请确保在annotate 之后添加适当的filterexclude 操作,例如:

    activities = Base_Activity.objects.all().annotate(
        a=Avg('user_activity__rating'), c=Count('user_activity__rating')
    ).filter(user_activity__rating__gt=0).order_by(
        '-a', '-c'
    )
    

    更新

    要获取所有项目,按他们的赞成票排序,不考虑反对票,我认为唯一的方法是使用原始查询,如下所示:

    from django.db import connection
    
    sql = '''
    SELECT o.id, SUM(v.rating > 0) s
    FROM user_activity o
    JOIN rating v ON o.id = v.user_activity_id
    GROUP BY o.id ORDER BY s DESC
    '''
    cursor = connection.cursor()
    result = cursor.execute(sql_select)
    rows = result.fetchall()
    

    注意:不要硬编码模型的表名,而是从模型中获取表名,例如,如果您的模型名为Rating,那么您可以使用Rating._meta.db_table 获取其表名。

    我在 sqlite3 数据库上测试了这个查询,我不确定那里的 SUM 表达式是否适用于所有 DBMS。顺便说一句,我有一个完美的 Django 站点来测试,我也使用 upvotes 和 downvotes。我使用一个非常相似的模型来计算赞成票和反对票,但我按 sum 值对它们进行排序,stackoverflow 样式。 siteopen-source,如果你有兴趣的话。

    【讨论】:

    • 我知道我可以使用Avg,我目前正在这样做,但结果不同。我只想查看赞成票,所以无视反对票。在我的示例中,我希望 2 up, 10 down1 up, 0 down 之前结束。如果我看平均值,情况就会相反。
    • @jvannistelrooy 我不明白:(2 - 10) / 12 = -0.66 小于 (1 + 0) / 2 = 0.5 那么我错过了什么?
    • 您完全正确,但是对于我正在构建的视图,我想忽略否决票,因此值将是 2, 1,而不是 -0.66, 0.5。也许我最初的问题不清楚,我会编辑它。
    • 这将导致查询过滤所有评分
    • 嘿 janos,我决定当它这么复杂时,应该有更好的方法来制作我的模型。我尝试了你的最后一个解决方案,但不幸的是 SUM() 函数中的表达式不起作用(我使用的是 postgres),即使我直接在数据库上运行查询也是如此。我正在寻找一种更好的方法来制作我的模型,但如果 SQL 有效,我会排除你的答案,以便其他人可以从中受益。
    猜你喜欢
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-23
    • 2012-04-01
    • 1970-01-01
    • 2021-12-18
    相关资源
    最近更新 更多