IT/작업기록
[Django] Prefetch는 어떤 역할을 하는가
aram
2026. 4. 20. 16:47
Q. prefetch_related는 알겠는데, Prefetch 객체는 왜 따로 쓰는가?
prefetch_related만 쓰면 관련 객체를 전부 가져온다. 하지만 관련 객체 중 일부만(예: 삭제되지 않은 항목만) 가져오고 싶을 때는 그 조건을 명시할 방법이 없다. 이때 Prefetch 객체를 쓰면, "이 관계를 prefetch할 때 어떤 queryset을 쓸지"를 직접 지정할 수 있다.
예를 들어 상세 항목 중 is_deleted=False인 것만 표시하고 싶다면, Prefetch 객체로 queryset을 명시한다.
# Mixin의 필터/검색/정렬 적용 후 is_deleted 필터 추가
# 관련 데이터(user, group, state)도 함께 조회(select_related)하여 성능 최적화
def get_queryset(self):
active_details = QuotationDetail.objects.filter(is_deleted=False).select_related("prod")
queryset = (
super()
.get_queryset()
.filter(is_deleted=False)
.select_related("user", "user__group", "state")
.prefetch_related(Prefetch("quo_details", queryset=active_details))
)
# 상태 필터
state_filter = self.request.GET.get("state_filter", "")
if state_filter:
queryset = queryset.filter(state__state_id=state_filter)
return queryset
정리
- select_related: 정방향 관계(ForeignKey, OneToOne)를 SQL JOIN으로 한 번에 가져온다. 여기서는 user, user__group, state.
- prefetch_related: 역방향/다대다 관계를 별도 쿼리로 가져와서 Python 레벨에서 합쳐준다. 여기서는 quo_details.
- Prefetch(관계이름, queryset=...): prefetch_related가 가져올 관련 객체의 범위를 직접 지정한다. 여기서는 quo_details 중 삭제되지 않은 것만, 그리고 그 안에서도 prod를 미리 select_related해서 N+1 쿼리를 한 번 더 줄였다.
즉 이 코드는 "목록 화면에서 삭제되지 않은 항목과 그 상세(삭제되지 않은 것만) + 연관 데이터를 최소한의 쿼리로 가져오기" 위한 최적화다. Prefetch 없이 그냥 prefetch_related("quo_details")만 썼다면, 삭제된 상세 항목까지 다 가져온 뒤 템플릿이나 코드에서 걸러내야 했을 것이다.