get_serializer_class: 요청별로 다른 Serializer 동적 반환하기
하나의 ViewSet에서 요청의 종류(action, method, 권한 등)에 따라 각기 다른 Serializer를 동적으로 반환하는 방법
필요성
하나의 모델에 대한 API에서 상황별로 다른 데이터 형식이 필요한 경우:
목록 조회 vs 상세 조회: 목록에서는 간단한 정보만, 상세에서는 모든 정보
읽기 vs 쓰기: 조회 시 비밀번호 제외, 생성/수정 시 비밀번호 포함
사용자 권한: 관리자에게는 민감 정보 포함, 일반 사용자에게는 제한된 필드만
동작 원리
DRF의 Serializer 결정 과정:
Request 수신 → ViewSet action 실행
Serializer 필요 시 get_serializer() 호출
get_serializer()가 내부적으로 get_serializer_class() 호출
커스텀 구현된 get_serializer_class()가 조건에 맞는 Serializer 반환
구현 예제
action에 따른 분기
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.select_related('author').all()
def get_serializer_class(self):
if self.action == 'list':
return PostListSerializer
return PostDetailSerializerHTTP 메서드에 따른 분기
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
def get_serializer_class(self):
if self.request.method == 'GET':
return UserReadSerializer
return UserWriteSerializer사용자 권한에 따른 분기
class SomeModelViewSet(viewsets.ReadOnlyModelViewSet):
queryset = SomeModel.objects.all()
def get_serializer_class(self):
user = self.request.user
if user.is_authenticated and user.is_staff:
return AdminUserSerializer
return RegularUserSerializer실무 팁
딕셔너리를 활용한 깔끔한 코드
class PostViewSet(viewsets.ModelViewSet):
serializer_map = {
'list': PostListSerializer,
'retrieve': PostDetailSerializer,
'create': PostCreateSerializer,
'update': PostUpdateSerializer,
}
default_serializer_class = PostDetailSerializer
def get_serializer_class(self):
return self.serializer_map.get(self.action, self.default_serializer_class)API 문서화 도구 연동
drf-spectacular 사용 시 @extend_schema 데코레이터로 각 action별 Serializer 명시 필요
장점
코드 재사용성: 관련 로직을 하나의 ViewSet으로 통합
유연성: 다양한 조건으로 분기 가능
깔끔한 URL 설계: URL 분리 없이 통일된 엔드포인트 사용
향상된 보안: 읽기/쓰기 Serializer 분리로 민감 정보 노출 방지
Last updated
