Django получает набор запросов из массива идентификаторов в определенном порядке

#python #django

#django #массивы

Вопрос:

вот быстрый вариант для вас:

У меня есть список идентификаторов, которые я хочу использовать для возврата набора запросов (или массива, если потребуется), но я хочу сохранить этот порядок.

Спасибо

Ответ №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)
  

Комментарии:

1. Лучший ответ, потому что он фактически возвращает набор запросов

2.Я все еще думаю, что django Case When недооценены!

3. Я собираюсь использовать distinct() с предложением order_by case when, но получил ошибку. пожалуйста, любая поддержка.

4. Я настоятельно рекомендую, это лучший ответ!

5. Это должен был быть выбранный ответ.

Ответ №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]
  

Это создает словарь объектов с их идентификатором в качестве ключа, поэтому их можно легко получить при создании отсортированного списка.

Комментарии:

1. Я надеялся, что это не так : ( спасибо за чистый код!

2. Просто остерегайтесь огромных запросов, так как при этом вы будете сохранять результат в памяти.

3. Может быть, использовать метод querysets in_bulk() вместо того, чтобы создавать словарь самостоятельно?

4. Проблема в том, что если объект в id_list не существует, он выдаст ошибку.

5. Почему бы не использовать понимание dict?

Ответ №3:

Если вы хотите сделать это с помощью in_bulk, вам действительно нужно объединить два ответа выше:

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

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

Комментарии:

1. Это не лучший ответ.

Ответ №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',))
  

Комментарии:

1. Вау. Это сложно. Спасибо!

2. Спасибо за этот ответ.

3. У меня не получилось: django.db.utils. Ошибка OperationalError: нет такой функции: ПОЛЕ 🙁

Ответ №5:

 id_list = [1, 5, 7]
objects = Foo.objects.filter(id__in=id_list)
sorted(objects, key=lambda i: id_list.index(i.pk))
  

Комментарии:

1. Пожалуйста, добавьте текст, объясняющий, как это работает и почему это решило бы проблему операционной системы. Помогите другим понять.

2. Лучший ответ. Спасибо!

3. Работает хорошо, хотя могла бы использовать дополнительную информацию

4. это будет работать только для упорядоченного списка идентификаторов. Можете ли вы подтвердить, будет ли это работать в любой последовательности… мне кажется, это неверно.

Ответ №6:

Другим лучшим / более чистым подходом может быть

 pk_list = [10, 2, 1]
sorted_key_object_pair = MyModel.objects.in_bulk(pk_list)
sorted_objects = sorted_key_object_pair.values()
  

Простой, чистый, меньше кода.

Комментарии:

1. Хорошо, при условии, что вам не нужен набор запросов.