Сортировать набор запросов по значениям в списке - PullRequest
9 голосов
/ 11 мая 2011

Можно ли отсортировать набор запросов django по списку элементов, предоставленных в запросе? Например, если я сделаю

m.objects.filter(id__in=[3,1,8])

Я не хочу, чтобы порядок запросов был элементом идентификатора 3, элементом идентификатора 1 и элементом идентификатора 8.

Спасибо

Ответы [ 8 ]

5 голосов
/ 11 мая 2011

Нет. Невозможно сделать то, что вы хотите, за исключением какого-то надуманного механизма, такого как:

qs = m.objects.filter(id__in=[3,1,8])
qs_sorted = list()
for id in [3,1,8]:
    qs_sorted.append(qs.get(id=id))

Вам также необходимо добавить некоторую обработку исключений, на случай, если один из указанных идентификаторов фактически не будет возвращен.

Минус в том, что это эффективно сведет на нет ленивую загрузку набора запросов. На самом деле, очень вероятно, что он сгенерирует несколько запросов к БД (хотя и не проверял). Кроме того, вы получите обычный список питонов вместо набора запросов, поэтому фильтрация невозможна.

3 голосов
/ 07 сентября 2018

Поскольку в Django> = 1.11 существует Case и When, вы можете сделать это более похожим на форму способом, сохранив все преимущества вашего набора запросов:

from django.db import models

order = ['b', 'a', 'z', 'x', 'c']
whens = []
for sort_index, value in enumerate(order):
    whens.append(models.When(my_field=value, then=sort_index))

qs = MyModel.objects.annotate(_sort_index=models.Case(*whens, output_field=models.IntegerField()))
qs.order_by('_sort_index')

Это сгенерирует что-то вроде этого:

from django.db import models

order = ['b', 'a', 'z', 'x', 'c']
qs = MyModel.objects.annotate(
    _sort_index=models.Case(
        models.When(my_field='b', then=0),
        models.When(my_field='a', then=1),
        models.When(my_field='z', then=2),
        models.When(my_field='x', then=3),
        models.When(my_field='c', then=4),
        output_field=models.IntegerField()
    )
).order_by('_sort_index')

Я бы предложил использовать это только с небольшим количеством элементов списка, потому что это взрывает запрос к базе данных.

https://docs.djangoproject.com/ko/1.11/ref/models/conditional-expressions/#case

3 голосов
/ 12 мая 2011

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

Если вы, например, используете MySQL, вы сможете сделать

Model.objects.raw('select * from myapp_model where id in (3,1,8) order by field(id,3,1,8)')
2 голосов
/ 11 мая 2011

Большинство ваших вариантов сортировки предполагают, что есть заказ на то, что вы сортируете. Если вы можете определить порядок, вы можете использовать order_by и поле в вашей модели, или sorted, используя python. Если вы хотите просто изменить порядок вещей (без всякой логики), вы все равно можете использовать sorted:

for id in [3,1,8]:
    sorted(qs, key=lambda x: x.id == id)
1 голос
/ 12 мая 2011

Спасибо всем за ваши ответы. Я придумал другое решение. Это не самый лучший, но нужно всего лишь сделать один запрос к базе данных. У меня есть список с идентификаторами, которые я хочу заказать в соответствии с моими потребностями. Затем я делаю запрос и заполняю словарь данными и, наконец, перебираю l, собирая объекты упорядоченным образом.

l =[7,1,4]
p_dict = {}
p = Poi.objects.filter(id__in=l)
for i in p:
    p_dict[i.id] = i

Используя это, я буду использовать много памяти, верно? Но я получаю доступ к базе данных.

@ a-lee Я изучу ваше решение и постараюсь преобразовать его в postgresql.

1 голос
/ 11 мая 2011

Возможно, вы можете использовать order-by, как упомянул Zeekay.

Если все в порядке, ваш QuerSet будет превращен в список, тогда вы можете использовать что-то вроде этого

sorted(queryset, key=lambda x: x.id) 
0 голосов
/ 16 апреля 2019
_list = [3,1,2]
sorted(queryset, key=lambda x: _list.index(x.id)) 
0 голосов
/ 03 февраля 2012

Хм, я не знаю, действительно ли это было недавно изменено или что-то в этом роде (это определенно имело место, по крайней мере, с августа), но вы можете запрашивать, используя именно синтаксис OP ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...