如何使用Django ORM实现带条件的order_by排序?
用Django ORM实现自定义条件排序
针对你提供的Foo模型,要实现和SQL语句select * from foo order by n=7, n=17, n=3, n等价的排序逻辑(即优先展示n=7的记录,接着是n=17,然后是n=3,最后剩余记录按n升序排列),可以通过Django的Case和When表达式来实现,具体有两种写法:
方法一:通过annotate生成排序字段后排序
先通过annotate为每条记录生成三个标记字段,分别标识是否匹配n=7、n=17、n=3,再基于这些字段排序:
from django.db.models import Case, When, IntegerField # 生成排序标记字段,匹配则返回1,否则返回0 Foo.objects.annotate( is_7=Case(When(n=7, then=1), default=0, output_field=IntegerField()), is_17=Case(When(n=17, then=1), default=0, output_field=IntegerField()), is_3=Case(When(n=3, then=1), default=0, output_field=IntegerField()) # 对标记字段降序排序(让匹配的记录排在前面),最后按n升序 ).order_by('-is_7', '-is_17', '-is_3', 'n')
方法二:直接在order_by中嵌入条件表达式
不需要额外生成字段,直接把Case表达式写入order_by,写法更简洁:
from django.db.models import Case, When, Value, IntegerField Foo.objects.order_by( # 匹配n=7时返回0,否则返回1,升序排序让匹配项靠前 Case(When(n=7, then=Value(0)), default=Value(1), output_field=IntegerField()), Case(When(n=17, then=Value(0)), default=Value(1), output_field=IntegerField()), Case(When(n=3, then=Value(0)), default=Value(1), output_field=IntegerField()), # 最后按n升序排列 'n' )
逻辑说明
SQL中的n=7这类条件会返回布尔值(或等价的整数1/0),排序时需要让匹配条件的记录优先展示。Django的Case/When可以模拟这个逻辑:
- 方法一中,匹配条件的记录标记为1,降序排序时1会排在0前面,实现优先展示。
- 方法二中,匹配条件的记录标记为0,升序排序时0会排在1前面,同样实现优先展示。
两种写法最终生成的SQL逻辑和你给出的目标SQL一致,都能满足排序需求。
内容的提问来源于stack exchange,提问作者run_the_race
相关产品推荐
相关产品推荐

