wafflestudio/seminar-2020

prefetch_related를 적용했음에도 불구하고 계속 쿼리를 날립니다.

Opened this issue · 4 comments

queryset = Seminar.objects.prefetch_related('userSeminar').prefetch_related('userSeminar__user').order_by('-created_at')

위와 같이 쿼리셋을 가져왔음에도 불구하고
아래 부분에서 UserSeminar에 대한 쿼리를 계속 날립니다.
왜 그런건지, 해결 방법은 무엇인지 궁금합니다.

# views.py
    def list(self, request):
      seminars = self.get_queryset()
      return Response(MiniSeminarSerializer(seminars, many=True).data)

# serializers.py
    def get_participants_count(self, seminar):
        return seminar.userSeminar.filter(role='participant').count()

자답합니다.
맨 처음 queryset을 가져올 때, django.db.models.Prefetch 을 통해 prefetch_related로 가져오는 object list를 가져와 저장해둘 수 있습니다. 아래와 같이 사용합니다.
Prefetch(<related name> , queryset = <object들을 가져오는 queryset> , to_attr = <저장할 이름>)

ex)

from django.db.models import Prefetch
...
queryset = Seminar.objects.prefetch_related(
          Prefetch( 'userSeminar', queryset = UserSeminar.objects.select_related('seminar'), to_attr = 'seminar_userSeminar')
        )

그럼 아래처럼 serializers.py에서도 사용이 가능합니다.
seminar.seminar_userSeminar

다만 queryset으로 가져오는 게 아니라 list로 가져옵니다.
따라서 queryset에서 사용할 수 있는 method를 list에 대해 직접 정의해서 써야 합니다.

왜 Prefetch 없이는 안되는지는 모르겠습니다! 알게되면 붙이겠습니다 ㅎㅎ

이때 queryset = UserSeminar.objects.select_related('seminar') 옵션을 추가하신 이유는 무엇인가요?

Seminar.objects.all()을 가져오면 seminar에 대한 정보가 이미 있을텐데, prefetch에서 seminar를 다시 join하면 정보가 중복해서 받아지지 않나요?

@gyusang 넵 저도 추후에 .all()로 수정했습니다 ㅎㅎ