Django order by 高级用法
- 最近业务上出现了一个比较特殊的排序需求:推荐池的内容要排在最前面,其他的 id 升序
准备
定义model
class TestCaseWhen(models.Model): name = models.CharField(max_length=255)
生成数据
from test_case_when.models import TestCaseWhen data_list = [] for num in range(10000): name = 'name:{}'.format(num) data_list.append(TestCaseWhen(name=name)) TestCaseWhen.objects.bulk_create(data_list)
检查数据
TestCaseWhen.objects.all().count() Out[7]: 10000 TestCaseWhen.objects.all().values_list('id', 'name') Out[8]:
需求
- 现在有这样一个列表 TestCaseWhen id_list [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000]
- 现在要让 TestCaseWhen 的 queryset 先按照 id_list 中的 id 位置进行排序,不在 id_list 的按照 id 升序
分析
- 普通的 .order_by('id') 肯定不能解决这个需求
- 又不想把 queryset 转换为列表排序
- 不谈 orm ,sql 该怎么写
想到了 sql 中的 case when 函数
SELECT id, name FROM test_case_when_testcasewhen ORDER BY CASE WHEN id = 10 THEN 0 WHEN id = 20 THEN 1 WHEN id = 30 THEN 2 WHEN id = 40 THEN 3 WHEN id = 50 THEN 4 WHEN id = 60 THEN 5 WHEN id = 70 THEN 6 WHEN id = 80 THEN 7 WHEN id = 90 THEN 8 WHEN id = 100 THEN 9 WHEN id = 1000 THEN 10 ELSE 11 END, id ASC ;
- 数据库走一波
- 这样一看好像成功了
- 那现在需要思考的就是咋用 django orm 转化成这样的 sql 语句了
- 先去查查文档, django case when 用法
- but , 并没有。。。。
- 那只能去问万能的网友了
- 最终找到了这个
运用到我们这里是这样的
from django.db.models import Case, When id_list = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000] order_rule = Case(*[When(id=id, then=pos) for pos, id in enumerate(id_list)], default=len(id_list)) qs = TestCaseWhen.objects.all().order_by(order_rule, 'id')
打印生成的 sql
print(qs.query) SELECT "test_case_when_testcasewhen"."id", "test_case_when_testcasewhen"."name" FROM "test_case_when_testcasewhen" ORDER BY CASE WHEN "test_case_when_testcasewhen"."id" = 10 THEN 0 WHEN "test_case_when_testcasewhen"."id" = 20 THEN 1 WHEN "test_case_when_testcasewhen"."id" = 30 THEN 2 WHEN "test_case_when_testcasewhen"."id" = 40 THEN 3 WHEN "test_case_when_testcasewhen"."id" = 50 THEN 4 WHEN "test_case_when_testcasewhen"."id" = 60 THEN 5 WHEN "test_case_when_testcasewhen"."id" = 70 THEN 6 WHEN "test_case_when_testcasewhen"."id" = 80 THEN 7 WHEN "test_case_when_testcasewhen"."id" = 90 THEN 8 WHEN "test_case_when_testcasewhen"."id" = 100 THEN 9 WHEN "test_case_when_testcasewhen"."id" = 1000 THEN 10 ELSE 11 END ASC, "test_case_when_testcasewhen"."id" ASC
查看输出数据
print(qs.values_list('id', 'name'))
- 这样看来问题就解决了
注意
- 此处可能会因为数据量的不同而产生性能问题