Проблема с получением экземпляров модели в определенном порядке

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

lst = ['AA1111111', 'AD2222222', 'AA3333333', 'AA4444444', 'АВ5555555']

Я пытался сделать что-то вроде этого:

empty_queryset = Users.objects.none()
for passport_number in lst:
    user = Users.objects.filter(passport_number__exact=passport_number)
    empty_queryset |= user

Я ожидал этого:

<QuerySet [<Users: AA1111111>, <Users: AD2222222>, <Users: AA3333333>, <Users: AA4444444>, <Users: АВ5555555>]>

Но это происходило в хаотичном порядке:

<QuerySet [<Users: АВ5555555>, <Users: AA1111111>, <Users: AD2222222>, <Users: AA3333333>, <Users: AA4444444>]>

Тогда я попробовал следующее:

Users.objects.filter(passport_number__in=[i for i in lst])

Но все равно не работает

Можете ли вы попробовать это?

from yourapp.models import User

lst = ['AA1111111', 'AD2222222', 'AA3333333', 'AA4444444', 'АВ5555555']

users_queryset = User.objects.filter(passport_number__in=lst)

users_list = sorted(users_queryset, key=lambda x:lst.index(x.passport_number))

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

SELECT *
FROM users
WHERE passport_number IN ('AA1111111',
                          'AD2222222',
                          'AA3333333',
                          'AA4444444',
                          'АВ5555555')
<<<Поскольку нет условия

, база ORDER BY данных может представить данные в любом порядке. Обычно, если задействованы индексы, данные могут быть упорядочены как индекс, но это скорее деталь реализации.

Вы можете работать с .union(…) [Django-doc] для работы с:

SELECT *
FROM users
WHERE passport_number = 'AA1111111'
UNION
SELECT *
FROM users
WHERE passport_number = 'AD2222222'
-- …

тогда это выглядит так:

Users.objects.none().union(
    *[User.objects.filter(passport_number=p) for p in lst], all=True
)

Другим вариантом может быть сортировка элементов на уровне Django/Python с помощью:

lst = ['AA1111111', 'AD2222222', 'AA3333333', 'AA4444444', 'АВ5555555']
order = {k: i for i, k in enumerate(lst)}

items = sorted(
    Users.objects.filter(passport_number__in=lst),
    key=lambda x: order.get(x.passport_number),
)

но тогда это будет список из Users, а не QuerySet, поэтому дополнительная фильтрация, пагинация и т.д. не может быть выполнена через QuerySet API.


Note: Normally a Django model is given a singular name [django-antipatterns], so User instead of Users.

Вернуться на верх