Создание QuerySet вручную в Django из списка идентификаторов - PullRequest
3 голосов
/ 08 мая 2020

Допустим, у меня есть модель My_model, и у меня есть список идентификаторов для этой модели;

my_ids = [3,2,1,42]

Теперь я хочу получить QuerySet с My_model.objects идентификаторов. Я уже нашел это решение , но оно не работает для меня, потому что я хочу, чтобы объекты в QuerySet были в том же порядке, что и идентификаторы в my_ids.

Как могу ли я превратить список идентификаторов в QuerySet в Django и Python?

Ответы [ 2 ]

3 голосов
/ 08 мая 2020

Он действительно не заботится о порядке, поскольку запрос выглядит следующим образом:

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

База данных может возвращать значения в любом порядке. В зависимости от используемой базы данных механизм индексации et c. порядок может быть "детерминированный c", но возможно даже, что он будет возвращать записи полностью случайным образом.

Вы можете заказать их, используя довольно сложное выражение:

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, и его можно использовать для ленивых запросов, но остается вопрос, почему вы хотите отсортировать элементы на основе порядка первичных ключей. Обычно модель (или связанная с ней модель) содержит более «интересные» способы упорядочивания элементов.

2 голосов
/ 08 мая 2020

Вы можете использовать in_bulk():

queryset = Foo.objects.in_bulk(my_ids)

Однако это будет иметь ту же проблему. Это ограничение не в Django, а в SQL. База данных вернет вам данные в любом случае, если вы явно не закажете их, и на самом деле нет хорошего способа произвольно упорядочить вещи. Вы могли бы делать странные вещи с CASE в SQL, но это, возможно, будет медленным.

Вероятно, самый простой способ - преобразовать набор запросов в список, а затем выполнить свой заказ в Python , что-то вроде:

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

Изменить: ответ Виллема делает странные вещи с case, который, вероятно, быстрее, чем этот, но я все равно не хотел бы захватывать материал в произвольном порядке, если вам важна скорость.

...