【问题标题】:Django ORM order by expressionDjango ORM 按表达式排序
【发布时间】:2016-10-10 15:16:52
【问题描述】:

嗨,我可以在 ORM 中按

players = GamePlayer.objects.raw('SELECT * FROM `Farmer_gameplayer` WHERE (`Farmer_gameplayer`.`game_id` = %d) ORDER BY `turn` < %d' % (game.pk, game.turn))

我想点这个:

players = GamePlayer.objects.filter(game=game) ORDER BY `turn` < 2

【问题讨论】:

  • 当你需要做一些比 orm 可以轻松处理的更深奥的事情时,使用原始 sql 是完全可以的..

标签: python django django-orm


【解决方案1】:

注意:您可以调整您的应用程序以使用ORDER BY turn,因为在质量上结果集与ORDER by turn &lt; 2 没有太大区别。您只会看到不同之处在于 ORDER BY turn 会根据 turn 列改变所有行的排序,而 ORDER BY turn &lt; 2 按布尔表达式 turn &lt; 2 排序,除此之外不会重新排序所有行。 下面我将介绍如何使用表达式来订购 Django 查询集,例如turn &lt; 2

用表达式注释,然后按它排序:

这个想法是注释一个名为turn_is_less_than_2 的字段either True or False,然后按它排序。所述注释将表示您稍后要订购的表达式turn &lt; 2 (ORDER BY turn &lt; 2)

from django.db.models import Case, When, BooleanField

GamePlayer.objects.filter(game=game).annotate(turn_is_less_than_2=Case(
    When(turn__lt=2, then=True),
    default=False,
    output_field=BooleanField()
)).order_by('turn_is_less_than_2') 

# or order_by('-turn_is_less_than_2') for DESC order instead of ASC

分解解释:

首先我只是接受您的询问

GamePlayer.objects.filter(game=game)

然后我要做的是用turn_is_less_than_2 字段注释它,如果turn &lt; 2 则为True,否则为False

GamePlayer.objects.filter(game=game).annotate(turn_is_less_than_2=...)

然后,当我们对过滤后的查询集进行注释时,我们现在可以按该字段排序:

GamePlayer.objects.filter(game=game).annotate(...).order_by('turn_is_less_than_2')

【讨论】:

  • 如果它是您正在对其进行过滤的相关对象怎么办?
  • @Rollo 应该是一样的,如果你不需要表达式,你可以在Django中使用__(双下划线)符号来遵循关系,例如order_by('author__age')。或者,如果您需要表达式,您可以在 When() 中使用它,例如When(author__age__lt=40, then=True)
  • 它似乎做了这种复制大量对象的内部连接。我会尝试重现,看看它是否是一个错误。
  • 是否可以通过编程方式调整相关模型中“self”上定义的表达式?
猜你喜欢
  • 2011-02-24
  • 2021-09-13
  • 1970-01-01
  • 2017-11-23
  • 2023-04-11
  • 2023-04-03
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多