[Django] ViewSet 과 Router
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
[Django] ViewSet 과 Router
Django-APIView-Mixins-genericsAPIView-ViewSet을-알아보자
저번 포스팅에서 ViewSet 에 대해서 간단히 알아보았습니다. 이번에는 좀 더 자세히 알아보도록 하겠습니다.
ViewSet
저번 포스팅에서도 언급했지만 ViewSet 은 다른 것들과 좀 달랐습니다.
일반적인 CBV 가 아니기 때문에 as_view 를 통해서 뷰를 만들지 않고 router를 사용했습니다.
as_view 를 사용하지 않는 이유는 ViewSet 은 하나의 뷰가 아닌 set, 여러 개의 뷰를 만들 수 있는 확장된 CBV이기 때문입니다.
사실 ViewSet 도 as_view를 사용하여 각각의 뷰를 만들어줄 수 있습니다.
.as_view({ 'http method': '함수' })
ViewSet 은 두 가지 종류로 이루어져 있습니다. 두 종류 모두 자체적인 구현은 없고 Mixin 을 적절히 상속받아 여러 기능을 수행하게 됩니다.
viewsets.ReadOnlyModelViewSet 목록 mixins.ListModelMixin : list() 함수 특정 레코드 mixins.RetrieveModelMixin : retrieve() 함수
viewsets.ModelViewSet 목록 mixins.ListModelMixin : list() 함수 특정 레코드 mixins.RetrieveModelMixin : retrieve() 함수 레코드 생성 mixins.CreateModelMixin : create() 함수 레코드 수정 mixins.UpdateModelMixin : update() 함수, partial_update() 함수 partial_update() 부분적인 필드값만 받아 수정이 가능하며 request method 중 Fetch 와 대응된다. 레코드 삭제 mixins.DestroyModelMixin : destroy() 함수
ModelViewSet 이 ReadOnlyModelViewSet 의 기능들을 함축하므로 ModelViewSet 에 대한 간단한 예시를 살펴보겠습니다.
우선 Post 모델을 정의해주겠습니다.
# models.py from django.db import models class Post(models.Model): title = models.CharField(max_length=100) content = models.TextField() is_public = models.BooleanField(default=False) create_at = models.DateTimeField(auto_now_add=True) update_at = models.DateTimeField(auto_now=True)
이에 대해서 Serializer 를 만들어주고
# Serializers.py from rest_framework.serializers import ModelSerializer from .models import Post class PostSerializer(ModelSerializer): class Meta: model = Post fields = '__all__'
ViewSet 을 정의해줍니다. 위에서 알아봤던 ModelViewSet 의 모든 기능을 다 연결시켜주었습니다.
# views.py from django.shortcuts import render from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet from .models import Post from .serializers import PostSerializer class PostViewSet(ModelViewSet): queryset = Post.objects.all() serializer_class = PostSerializer post_list = PostViewSet.as_view({ 'get': 'list', 'post': 'create', }) post_detail = PostViewSet.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy', })
마지막으로 url 만 연결해주면 아래와 같은 결과 화면을 볼 수 있습니다.
# urls.py from django.urls import path, include from . import views urlpatterns = [ path('post/', views.post_list), path('post//', views.post_detail), ]
Router
이 역시 저번 포스팅에서 봤듯이 URL 매핑을 편리하게 할 수 있습니다. 기존에는 as_view 를 통해 각 request method 마다 대응되는 함수를 연결시켜주었다면 router 는 이를 알아서 연결시켜줍니다.
디폴트 매핑은 위에서 본 것과 동일합니다.
list route url : /prefix/ name : {model name}-list , 단 model name 은 소문자입니다. 'get': 'list' 'post': 'create'
detail route url : /prefix/pk/ name : {model name}-detail 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy',
위의 urls 를 아래와 같이 수정하였습니다. 이 때 prefix 자리에는 post 가 쓰였고 이에 따라 url이 결정됩니다.
# urls.py from django.urls import path, include from rest_framework.routers import DefaultRouter from . import views router = DefaultRouter() router.register(r'post',views.PostViewSet) urlpatterns = [ path('',include(router.urls)), ]
더 이상 as_view 를 통해 단일 뷰를 뽑아낼 필요가 없어졌습니다.
# views.py from django.shortcuts import render from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet from .models import Post from .serializers import PostSerializer class PostViewSet(ModelViewSet): queryset = Post.objects.all() serializer_class = PostSerializer
다음과 같이 Router 를 사용하게 되면 Api Root 를 제공해줍니다. 해당 app 에 대한 root url 로 갈 경우 아래 이미지와 같이 Router 에 등록된 ViewSet을 확인 할 수 있습니다.
Api Root
ViewSet 더 알아보기
디폴트 매핑의 경우, list route 에 대해서 2개, detail route 에 대해서 4개에 대해서 매핑을 해주게 됩니다. 하지만 실제로는 6개보다 더 많은 경우가 비일비재합니다. 따라서 추가적으로 매핑을 하는 방법에 대해서 알아보도록 하겠습니다.
추가적으로 매핑하는 방법은 간단합니다. ViewSet 의 맴버함수로 구현한 후 decorator 를 붙여주면 됩니다. 이 때 URL 은 Router가 알아서 결정해줍니다.
decorator action
매핑하기 위해서 action decorator 를 사용하는데 이에 대해서 알아보도록 하겠습니다.
import 경로 from rest_framework.decorators import action
detail action 은 첫번째 인자로 detail 값을 받습니다. Boolean 으로서 True 일 경우, pk 값을 지정해줘야하는 경우에 사용하고 False일 경우, 목록 단위로 적용하게 됩니다.
methods request method 를 지정해줄 수 있습니다. 디폴트 값은 get 으로 자세한 사용방법은 아래 예시를 통해 보겠습니다.
이 때 detail 값에 따라 Router가 URL 을 결정하는 방법이 다릅니다.
detail=True url : /prefix/{pk}/{function name}/ name : {model name}-{function name}
detail=False url : /prefix/{function name}/ name : {model name}-{function name}
이 때 모든 이름은 소문자이며, function name의 언더바(_)는 하이픈(-) 으로 교체됩니다.
is_public 값이 True 인 레코드만 필터링하는 public_list 와 특정 레코드의 is_public 을 True로 바꿔주는 set_public 을 정의하였습니다.
# views.py from django.shortcuts import render from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet from rest_framework.decorators import action from rest_framework.response import Response from .models import Post from .serializers import PostSerializer class PostViewSet(ModelViewSet): queryset = Post.objects.all() serializer_class = PostSerializer # url : post/public_list/ @action(detail=False) def public_list(self, request): qs = self.queryset.filter(is_public=True) serializer = self.get_serializer(qs, many=True) return Response(serializer.data) # url : post/{pk}/set_public/ @action(detail=True, methods=['patch']) def set_public(self, request, pk): instance = self.get_object() instance.is_public = True instance.save() serializer = self.get_serializer(instance) return Response(serializer.data)
from http://ssungkang.tistory.com/235 by ccl(A)
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기