(참고: stackoverflow.com/questions/18235419/how-to-chain-django-querysets-preserving-individual-order)

쿼리셋을 여러개를 만들어서 만드는 순서대로 합쳐 리스트를 만들고 반환해야 되는 때를 가정해봅시다. 데이터베이스에 딱 1번만 접근하면서, 쿼리셋을 만드는 순서 == 실제로 반환되는 모델의 순서가 되도록 해야 한다고 생각해봅시다.

 

>>> qs1.union(qs2, qs3)

1. SQL의 UNION operator를 사용하도록 QuerySet.union을 사용한다

db 접근은 한번만 합니다. 문제는 합쳐지는 쿼리셋의 순서가 보장되지 않습니다

 

result = []
result.append(qs1.first())
result.append(qs2.first())

2. 쿼리셋을 미리 evaluation 해놓고 리스트에 추가한다

순서는 보장되지만 db 히트 수가 많아집니다

 

q1 = Q(...)
q2 = Q(...)
q3 = Q(...)
qs = (Model.objects
      .filter(q1 | q2 | q3)
      .annotate(
          search_type_ordering=Case(
              When(q1, then=Value(2)),
              When(q2, then=Value(1)),
              When(q3, then=Value(0)),
              default=Value(-1),
              output_field=IntegerField()))
      .order_by('-search_type_ordering', ...))

3. annotate로 정렬할 필드를 추가한다

db 히트도 한번이고, 순서도 보장됩니다.

 

더 좋은 방안이나 의견이 있으시면 댓글 부탁드립니다 (장고뉴비입니다 ㅠ)

반응형