Пользовательский заказ Django QuerySet по идентификатору

Учитывая список идентификаторов /pks, я хотел бы сгенерировать объект QuerySet объектов, упорядоченных по индексу в списке.

Обычно я начинал с:

pk_list = [5, 9, 2, 14]
queryset = MyModel.objects.filter(pk__in=pk_list)

Это, конечно, возвращает объекты, но в порядке свойств метаопределения моделей, и я хочу получить записи в порядке pk в pk_list.

Конечным результатом должен быть один объект QuerySet (а не список), поскольку я хочу передать упорядоченное поле формы QuerySet в Django ModelMultipleChoiceField.

Ответы

Ответ 1

Существует не встроенный способ сделать это.

Если вы используете MySQL, вы можете использовать эту базу данных FIELD() для настройки пользовательской последовательности упорядочения на вашей модели и сортировки по ней. Это будет работать:

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

Ответ 2

Я не знаю, как это сделать, используя условие фильтра. Если ваша база данных вернет строки в порядке предложения IN, тогда вы сможете комбинировать метод Django extra с ROWNUM, предоставленный вашей базой данных, чтобы достичь этого.

Например,

queryset = MyModel.objects.filter(pk__in=[pk_list]).extra(
       select: {'rownum': 'row_num()'}).order_by('rownum')

Где row_num() предполагается функцией базы данных, которая возвращает номер строки текущей строки. Postgresql 8.4+ поддерживает row_num(), но я не знаю, как упорядочить строки, возвращенные с использованием того же порядка, что и значения в предложении IN.

Я думаю, что лучший способ был бы для подкласса ModelMultipleChoiceField и добавления пользовательской логики сортировки при рендеринге.