https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/
ViewSets란 REST framework에서 제공하는 굉장히 유용한 abstraction으로,
- 개발자가 API의 state와 interaction을 모델링하는데 집중할 수 있게 하고,
- URL construction이 보통의 관습에 따라 자동적으로 다뤄질 수 있게 한다.
- View class와 비슷하나, get/put 대신 read/update를 지원한다.
- ViewSet은 처음 views의 집합으로 인스턴스화되는 마지막 순간에 method handler 집합에 의해 바인딩된다.
- 이를 위해 보통 Router class를 사용하는데, router class는 개발자가 URL conf를 정의하는데 복잡한 상황을 해결해준다.
ViewSets 사용하기
기존의 set of views를 view sets로 refactor해보자
UserList, UserDetail => UserViewSet
# snippets/views.py
from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet): # read-only
"""
This viewset automatically provides `list` and `detail` actions.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
* ReadOnlyModelViewSet class: read-only
SnippetList, SnippetDetail, SnippetHighlight => SnippetViewSet
# snippets/views.py
from rest_framwork.decorators import action
class SnippetViewSet(viewsets.ModelViewSet): # read-write
"""
This viewset automatically provides `list`, `create`, `retrieve`, `update` and `destroy` actions.
Additionally, we also provide an extra `hightlight` action.
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
@action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
* ModelViewSet class: read-write
* @action decorator: to create custom action
- decorator은 cusotom endpoints를 만들때 사용한다.(표준 create/update/delete 스타일이 아닐 때)
- @action decorator을 사용한 custom actions은 default로 GET requests에 응답하는데, methods argument를 사용해서 POST requests에 응답하게 만들 수 있다.
- custom actions를 위한 URL은 default로 method name에 따르지만, 이를 바꾸려면 url_path를 decorator keyword argument에 포함시키면 된다.
ViewSets를 URLs에 명시적으로 바인딩하기
handler method는 URLconf에 정의되어야만 actions에 바인딩될 수 있다.
snippets/urls.py를 수정해서 ViewSet classes를 concrete views의 집합으로 바인딩하자
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets.views import SnippetViewSet, UserViewSet, api_root
from rest_framework import renderers
# bound resources into concrete views
snippet_list = SnippetViewSet.as_view({
'get': 'list',
'post': 'create'
})
snippet_detail = SnippetViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
})
snippet_highlight = SnippetViewSet.as_view({
'get': 'highlight'
})
user_list = UserViewSet.as_view({
'get': 'list'
})
user_detail = UserViewSet.as_view({
'get': 'retrieve'
})
# register the views with the URL conf as usual
urlpatterns = format_suffix_patterns([
path('', api_root),
path('snippets/', snippet_list, name='snippet-list'),
path('snippets/<int:pk>/', snippet_detail, name='snippet-detail'),
path('snippets/<int:pk>/highlight/', snippet_highlight, name='snippet-highlight'),
path('users/', user_list, name='user-list'),
path('users/<int:pk>/', user_detail, name='user-detail')
])
Routers 사용하기
앞서 말했듯이, 사실,
ViewSet을 사용했기 때문에 URL conf를 직접 디자인 할 필요는 없다.
자동적으로 해결해주는 Router class를 사용해보자
snippets/urls.py를 다음과 같이 바꿔보자
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)
# The API URLs are now determined automatically by the router
urlpatterns = [
path('', include(router.urls))
]
DefaultRouter class는 자동적으로 API root view를 만들어주기 때문에, views에서 api_root method를 삭제할 수 있다.
Trade-offs between views vs viewsets
viewsets의 장점
- URL conventions가 API에 유지되는 것을 보장
- 작성해야 할 코드의 양을 줄이는데 도움
- API가 제공해야하는 interactions와 representations에 집중할 수 있게 도움(URL conf 명세 대신에)
그러나 이게 항상 좋은 approach는 아니다. 마치 class-based views와 function-based views 사이의 트레이드오프를 비교하는 것과 같다.
viewsets를 사용하는 것은 views를 각각 빌드하는 것보단 덜 명백할 수 있다.
여기서 Django REST framework 튜토리얼 실습을 마친다!
끝!
'Python > Django' 카테고리의 다른 글
[Django Authentication] 회원가입, 로그인, 로그아웃 기능 구현 / 일일이 다 구현해보자 (0) | 2020.04.19 |
---|---|
[Django + PostgreSQL] PostgreSQL 설치 후 Django와 연동하기 / 기존 프로젝트 수정 (0) | 2020.04.16 |
[Django REST framework] 5. Relationships & Hyperlinked APIs (0) | 2020.04.11 |
[Django REST framework] 4. Authentication & Permissions (0) | 2020.04.10 |
[Django REST framework] 3. Class-based Views (0) | 2020.04.10 |