从 id 列表在 Django 中手动创建一个 QuerySet

Creating a QuerySet manually in Django from list of ids

假设我有一个模型 My_model 并且我有这个模型的 ID 列表;

my_ids = [3,2,1,42]

现在我想获得一个带有 My_model.objects 个 ID 的 QuerySet。 我已经找到 this solution,但它对我不起作用,因为我希望 QuerySet 中的对象与 my_ids.

中的 id 的顺序相同

如何在 Django 和 Python 中转换 QuerySet 中的 ID 列表?

您可以使用 in_bulk():

queryset = Foo.objects.in_bulk(my_ids)

但是这样也会有同样的问题。这不是 Django 的限制,而是 SQL 的限制。除非您明确订购,否则数据库会根据需要返回给您数据,并且没有真正的任意订购事物的好方法。

所以答案是,你不能,很容易。您可能会在 SQL 中使用 CASE 做一些奇怪的事情,但这可能会很慢。

可能最简单的方法是将查询集转换为列表,然后在 Python 中进行自定义排序,例如:

objs = sorted(list(queryset), key=lambda x: my_ids.index(x.id))

编辑:Willem 的回答用 case 做了奇怪的事情,可能比这更快,但如果你关心速度,我仍然不想以任意顺序获取东西。

它确实不关心顺序,因为查询看起来像:

SELECT model.*
FROM model
WHERE model.pk <b>IN (3, 2, 1, 42)</b>

数据库可以return 以任何顺序排列值。根据您使用的数据库、索引机制等,顺序可以是 "deterministic",但甚至有可能 return 记录完全随机。

你可以订购这些,用一个相当复杂的表达:

from django.db.models import Case, IntegerField, Value, When

my_ids = [3,2,1,42]

Model.objects.filter(
    pk__in=my_ids
).order_by(
    Case(
        *[<b>When(pk=pk, then=Value(i)) for i, pk in enumerate(my_ids)</b>],
        output_field=IntegerField()
    )<b>.asc()</b>
)

这仍然是一个QuerySet,可以用于惰性查询目的,但问题仍然是为什么要根据的顺序对元素进行排序主键。通常模型(或相关模型)包含更多 "interesting" 元素排序方式。