Django REST Framework에서 Serializer 중첩 처리하기

문제 상황

사용자 목록 API에서 각 사용자의 프로필 정보를 함께 반환해야 했다. 처음에는 단순하게 Serializer를 중첩해서 구현했다.

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = ['bio', 'avatar_url']

class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer(read_only=True)
    
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'profile']

기능은 정상 작동했지만, 사용자가 100명이면 쿼리가 101번 실행되는 전형적인 N+1 문제가 발생했다.

해결 방법

ViewSet에서 select_related를 사용해 쿼리를 최적화했다.

class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    
    def get_queryset(self):
        return User.objects.select_related('profile').all()

이렇게 수정하니 쿼리가 1번으로 줄어들었다. Django ORM의 select_related는 SQL JOIN을 사용해 관련 객체를 미리 가져온다.

추가 고려사항

  • ManyToMany나 역참조 관계는 prefetch_related 사용
  • 중첩 깊이가 깊어지면 응답 크기가 커지므로 필요한 필드만 선택
  • 쓰기 작업 시에는 중첩된 Serializer의 create/update 메서드 오버라이드 필요

Django Debug Toolbar를 사용하면 실제 실행되는 쿼리를 쉽게 확인할 수 있어서 성능 최적화에 유용했다.