【问题标题】:Django get a QuerySet from array of id's in specific orderDjango 按特定顺序从 id 数组中获取 QuerySet
【发布时间】:2011-06-22 10:59:08
【问题描述】:

这里给你一个快速的:

我有一个 id 列表,我想用它来返回一个 QuerySet(或数组,如果需要的话),但我想保持这个顺序。

谢谢

【问题讨论】:

    标签: django arrays


    【解决方案1】:

    从 Django 1.8 开始,您可以这样做:

    from django.db.models import Case, When
    
    pk_list = [10, 2, 1]
    preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(pk_list)])
    queryset = MyModel.objects.filter(pk__in=pk_list).order_by(preserved)
    

    【讨论】:

    • 最佳答案,因为它实际上返回了一个查询集
    • 我还是觉得django的CaseWhen被低估了!
    • 我将在 order_by case when 子句中使用distinct(),但出现错误。任何支持,请。
    • 我强烈推荐这是最好的答案!
    • 这应该是选择的答案。
    【解决方案2】:

    我认为您无法在数据库级别强制执行该特定顺序,因此您需要改为在 python 中执行。

    id_list = [1, 5, 7]
    objects = Foo.objects.filter(id__in=id_list)
    
    objects = dict([(obj.id, obj) for obj in objects])
    sorted_objects = [objects[id] for id in id_list]
    

    这会建立一个以 id 为键的对象字典,因此在建立排序列表时可以轻松检索它们。

    【讨论】:

    • 我希望不是这样 :( 感谢干净的代码!
    • 请注意大型查询,因为这样做时您会将结果存储在内存中。
    • 也许使用querysets in_bulk() 方法,而不是自己构建字典?
    • 这样的问题是,如果 id_list 中的对象不存在,则会抛出错误。
    • 为什么不使用字典理解?
    【解决方案3】:

    如果你想使用 in_bulk 做到这一点,你实际上需要合并上面的两个答案:

    id_list = [1, 5, 7]
    objects = Foo.objects.in_bulk(id_list)
    sorted_objects = [objects[id] for id in id_list]
    

    否则结果将是一个字典,而不是一个专门排序的列表。

    【讨论】:

    • 这不是一个更好的答案。
    【解决方案4】:

    这是一种在数据库级别执行此操作的方法。复制粘贴自:blog.mathieu-leplatre.info

    MySQL

    SELECT *
    FROM theme
    ORDER BY FIELD(`id`, 10, 2, 1);
    

    与 Django 相同:

    pk_list = [10, 2, 1]
    ordering = 'FIELD(`id`, %s)' % ','.join(str(id) for id in pk_list)
    queryset = Theme.objects.filter(pk__in=[pk_list]).extra(
               select={'ordering': ordering}, order_by=('ordering',))
    

    PostgreSQL

    SELECT *
    FROM theme
    ORDER BY
      CASE
        WHEN id=10 THEN 0
        WHEN id=2 THEN 1
        WHEN id=1 THEN 2
      END;
    

    与 Django 相同:

    pk_list = [10, 2, 1]
    clauses = ' '.join(['WHEN id=%s THEN %s' % (pk, i) for i, pk in enumerate(pk_list)])
    ordering = 'CASE %s END' % clauses
    queryset = Theme.objects.filter(pk__in=pk_list).extra(
               select={'ordering': ordering}, order_by=('ordering',))
    

    【讨论】:

    • 哇。那是激烈的。谢谢!
    • 感谢您的回答。
    • 对我来说失败了:django.db.utils.OperationalError:没有这样的功能:FIELD :(
    【解决方案5】:
    id_list = [1, 5, 7]
    objects = Foo.objects.filter(id__in=id_list)
    sorted(objects, key=lambda i: id_list.index(i.pk))
    

    【讨论】:

    • 请添加一些文字来解释它是如何工作的以及为什么它会解决 OP 的问题。帮助他人理解。
    • 最佳答案。谢谢!
    • 效果很好,不过可以使用其他信息
    • 这仅适用于有序的 idlist。你能确认它是否可以按任何顺序工作......对我来说似乎不是真的。
    猜你喜欢
    • 2011-04-07
    • 2012-06-29
    • 1970-01-01
    • 2022-09-28
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多