【问题标题】:Adding literal values to a QuerySet in Django在 Django 中向 QuerySet 添加文字值
【发布时间】:2015-10-12 10:25:25
【问题描述】:

我正在尝试根据在多场比赛中获得的积分为球队分配排名。积分多的队伍排名靠前,积分相同的队伍排名靠前。团队可以有相同的排名。

因为 Django(也不是 SQLite)支持 DENSE_RANK 窗口函数,我必须在 Python 中计算排名。虽然最初我对all() 返回的模型实例执行此操作,但我决定应该能够为annotate().order_by() 返回的QuerySet 添加排名,同时保留一个QuerySet 对象以供使用,例如get()

class TeamManager(models.manager):
    @staticmethod
    def add_ranking(qs):
        # First, populate rows and rankings lists
        # ...
        # Then, add it to the query set
        literal_selects = []
        for row_id, ranking in zip([row.id for row in rows], rankings):
            literal_selects.append('SELECT {} AS "thing_id", {} AS ranking'.format(row_id, ranking))
        extra_from = "(" + " UNION ALL ".join(literal_selects) + ")"

        return qs.extra(
            tables=[extra_from],
            select={'ranking': 'ranking'},
            where=['team.id = thing_id'])

    def ranked_list(self):
        qs = self.model.objects.annotate(
            num_games=Count('team__score_set'),
            total_points=Sum('team__score_set__points'),
            # Ideally, I would calculate ranking here
        ).order_by('-total_points')

        return TeamManager.add_ranking(qs)

这不起作用,因为 Django 的 ORM adds double quotesextra(table) 中的“表名”周围

是否有任何其他方法可以将文字值添加到预先存在的 QuerySet,或者我必须用对 raw() 的调用替换对注释的调用,然后从那里开始工作?这将是一个遗憾,因为我刚刚投入了大量时间来了解如何将我的原始原始 SQL 查询(使用 GROUP BYs 和所有内容)转换为更 Djangoesque 的做事方式。我很想用 Django 摆脱这种情况,而不是跟着我自己的旧 SQL 曲调跳舞。

【问题讨论】:

  • 不,我认为您将不得不使用raw... 一个更“可行”的选项是将查询烘焙到一个视图中,该视图可以作为单独的模特来自django-postgres.readthedocs.org/en/latest/views.html
  • 不是一个实际的答案,但是当我在计算排名时遇到类似的问题时,我最终创建了另一个只包含“积分/分数”的表格。当我们遍历一些大表时,它也使查询速度更快。因此,也许有一种方法可以让您创建和使用某种“积分”表。
  • 原谅我,但从我的角度来看似乎是排序问题,按total_points和-num_games排序,如果点数相同,则num_games最少的团队将首先(添加排序以 id 结尾,这样你就可以避免在同等级别和游戏中出现分页问题)

标签: python sql django django-models sqlite


【解决方案1】:

您可以使用 Value 添加文字值:

qs = self.model.objects.annotate(
    num_games=Count('team__score_set'),
    total_points=Sum('team__score_set__points'),
    ranking=Value(42, output_field=IntegerField())
).order_by('-total_points')

【讨论】:

  • 当我问这个问题时,这还不可用,但我绝对应该接受你的回答,因为这些数据库功能(现在不再是新的)绝对是我想要的,并且从此开始大量使用。
猜你喜欢
  • 2019-06-22
  • 2012-02-04
  • 2014-10-08
  • 1970-01-01
  • 2023-03-31
  • 2011-06-23
  • 1970-01-01
  • 2016-12-22
  • 2018-03-30
相关资源
最近更新 更多