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]: 

需求

  • 现在有这样一个列表 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 order by 高级用法_第1张图片
  • 这样一看好像成功了
  • 那现在需要思考的就是咋用 django orm 转化成这样的 sql 语句了
  • 先去查查文档, django case when 用法
  • but , 并没有。。。。
  • 那只能去问万能的网友了
  • 最终找到了这个

Django order by 高级用法_第2张图片

  • 运用到我们这里是这样的

    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'))
    
    
    
  • 这样看来问题就解决了

注意

  • 此处可能会因为数据量的不同而产生性能问题

你可能感兴趣的:(djangoorder-by)