Django는 특정 순서로 id 배열에서 QuerySet을 가져옵니다.


84

여기에 빠른 것이 있습니다.

QuerySet (또는 필요한 경우 배열)을 반환하는 데 사용하려는 ID 목록이 있지만 그 순서를 유지하고 싶습니다.

감사

답변:


72

나는 당신이 데이터베이스 수준에서 특정 순서를 강요 할 수 없다고 생각하기 때문에 대신 파이썬으로해야한다.

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]

이렇게하면 ID를 키로 사용하여 개체의 사전이 만들어 지므로 정렬 된 목록을 만들 때 쉽게 검색 할 수 있습니다.


나는 이것이 사실이 아니기를 바라고 있었다 :( 깨끗한 코드에 감사드립니다!
neolaser

3
이 작업을 수행 할 때 결과를 메모리에 저장하므로 거대한 쿼리에주의하십시오.
Jj.

14
사전을 직접 구성하는 대신 querysets in_bulk () 메서드를 사용할 수 있습니까?
Matt Austin

문제는 id_list의 객체가 존재하지 않으면 오류가 발생한다는 것입니다.
madprops 2016 년

dict comprehension을 사용하지 않는 이유는 무엇입니까?
wieczorek1990

186

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)

16
실제로
쿼리 세트를

2
나는 여전히 장고 Case When가 과소 평가 되었다고 생각합니다 !
Babu

distinct()order_by case when 절과 함께 사용 하지만 오류가 발생했습니다. 어떤 지원을 부탁드립니다.
elquimista

SELECT DISTINCT ON expressions must match initial ORDER BY expressions-여기에 오류 메시지가 있습니다
elquimista 2017 년

1
이것은 선택된 대답이어야합니다.
Subangkar KrS

28

in_bulk를 사용하여이 작업을 수행하려면 실제로 위의 두 답변을 병합해야합니다.

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

그렇지 않으면 결과는 특별히 정렬 된 목록이 아닌 사전이됩니다.


1
이것은 더 나은 대답이 아닙니다.
Tony

26

다음은 데이터베이스 수준에서 수행하는 방법입니다. 다음에서 붙여 넣기 복사 : 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',))

와. 그것은 강렬합니다. 감사!
Dan Gayle 2014 년

이 답변에 감사드립니다.
Subangkar KrS

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

1
이것이 작동하는 방식과 OP의 문제를 해결하는 이유를 설명하는 텍스트를 추가하십시오. 다른 사람들이 이해하도록 도와주세요.
APC

최고의 답변입니다. 감사!
webjunkie

하지만 추가 정보를 사용할 수 있습니다, 잘 작동
xtrinch

이것은 주문 된 idlist에 대해서만 작동합니다. 어떤 순서로도 작동하는지 확인해 주시겠습니까? 사실이 아닌 것 같습니다.
Doogle 2018 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.