@action 데코레이터로 특정 로직을 위한 깔끔한 엔드포인트 추가하기
ViewSet에서 기본 CRUD 외의 추가 기능을 구현할 때 @action 데코레이터를 사용하여 관련 로직을 깔끔하게 추가하고 URL을 자동 생성
@action이 필요한 이유
기본 CRUD 외에 필요한 추가 기능들:
최신 글 목록만 조회
게시글에 '좋아요', '신고하기' 기능
공유하기 등
기존 해결 방법의 문제점:
별도 APIView 생성: 파일과 클래스 증가, URL 설정 복잡화
update 로직에 억지로 추가: 메서드 비대화, API 직관성 저하
@action 기본 사용법
핵심 인자
detail=True: 특정 객체에 대한 액션 (/posts/{pk}/publish/)detail=False: 목록 전체에 대한 액션 (/posts/recent/)methods: 허용할 HTTP 메서드 지정serializer_class: 사용할 시리얼라이저 지정permission_classes: 사용할 권한 클래스 지정
특정 게시글 공개 (detail=True)
@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
post = self.get_object()
if post.is_published:
return Response({'detail': '이미 공개된 게시글입니다.'})
post.is_published = True
post.save(update_fields=['is_published'])
serializer = self.get_serializer(post)
return Response(serializer.data)최신 글 목록 조회 (detail=False)
@action(detail=False, methods=['get'])
def recent(self, request):
recent_posts = self.get_queryset().order_by('-created_at')[:5]
serializer = self.get_serializer(recent_posts, many=True)
return Response(serializer.data)실무 활용 팁
URL 경로 커스텀
@action(detail=True, methods=['post'], url_path='change-password')
def set_password(self, request, pk=None):
# URL: /users/{pk}/change-password/액션별 권한과 시리얼라이저 적용
@action(detail=True, methods=['post'],
permission_classes=[IsAdminUser],
serializer_class=PasswordSerializer)
def set_password(self, request, pk=None):
# 해당 액션에만 특별한 권한과 시리얼라이저 적용주의사항
@action 사용 vs 별도 APIView
@action 적합: 리소스와 강하게 결합된 행위, 단순한 로직
별도 APIView 적합: 독립적인 로직, 복잡한 다중 모델 처리
PreviousGenericViewSet과 Mixin 조합으로 나만의 CRUD 로직 만들기Nextget_serializer_class: 요청별로 다른 Serializer 동적 반환하기
Last updated
