from django.db.models import Case, When
ids = [5, 2, 3, 1, 4]
order = Case(*[When(id=id, then=pos) for pos, id in enumerate(ids)])
queryset = MyModel.objects.filter(id__in=ids).order_by(order)
qs.extra(select={'o':'(case when id=5 then 1 when id=2 then 2 when id=3 then 3 when id=1 then 4 when id=4 then 5 end)', order_by='o'}
YourModel.raw('select ... order by (case ...)')
4条答案
按热度按时间uqcuzwp81#
从Django 1.8开始,你有了Conditional Expressions,所以不再需要使用
extra
。htrmnn0y2#
这是可能的。从Django 1.8开始,你可以通过以下方式来做:
wsxa1bj13#
你可以用
extra()
或更简单的raw()
来做,但它们在更复杂的情况下不能很好地工作。对于你的代码,条件集是非常有限的,你可以很容易地在Python中排序。
h7appiyu4#
我回答这个老问题,分享Django的演变
从Django 3.2开始,有一个alias()非常适合这种情况:
与annotate()相同,但不是注解QuerySet中的对象,而是保存表达式以供以后与其他QuerySet方法重用。当不需要表达式本身的结果,但将其用于筛选、排序或作为复杂表达式的一部分时,这很有用。不选择未使用的值可以从数据库中删除冗余工作,从而提高性能。
根据Django文档,**alias()似乎比annotate()或order_by()**中的直接表达式更好:
filter()和order_by()可以直接接受表达式,但表达式的构造和使用通常不在同一个地方发生(例如,QuerySet方法创建表达式,供以后在视图中使用)。alias()允许增量地构建复杂的表达式,可能跨越多个方法和模块,通过别名引用表达式部分,并仅使用annotate()获得最终结果。