Django order by 高级用法

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]: <QuerySet [(1, 'name:0'), (2, 'name:1'), (3, 'name:2'), (4, 'name:3'), (5, 'name:4'), (6, 'name:5'), (7, 'name:6'), (8, 'name:7'), (9, 'name:8'), (10, 'name:9'), (11, 'name:10'), (12, 'name:11'), (13, 'name:12'), (14, 'name:13'), (15, 'name:14'), (16, 'name:15'), (17, 'name:16'), (18, 'name:17'), (19, 'name:18'), (20, 'name:19'), '...(remaining elements truncated)...']>
    

需求

  • 现在有这样一个列表 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'))
    
    <QuerySet [(10, 'name:9'), (20, 'name:19'), (30, 'name:29'), (40, 'name:39'), (50, 'name:49'), (60, 'name:59'), (70, 'name:69'), (80, 'name:79'), (90, 'name:89'), (100, 'name:99'), (1000, 'name:999'), (1, 'name:0'), (2, 'name:1'), (3, 'name:2'), (4, 'name:3'), (5, 'name:4'), (6, 'name:5'), (7, 'name:6'), (8, 'name:7'), (9, 'name:8'), '...(remaining elements truncated)...']>
    
    
  • 这样看来问题就解决了

注意

  • 此处可能会因为数据量的不同而产生性能问题
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值