8. ViewSets & Routers
1. Refactoring to user ViewSets
- 뷰 세트를 리팩토링해 보자.
- 먼저, 다음과 같이
UserList
및UserDetail
뷰를 하나의UserViewSet
으로 리팩토링한다.
snippets/views.py
from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
This viewset automatically provides 'list' and 'retrieve' actions.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
ReadOnlyModelViewSet
클래스를 사용하여 기본 '읽기 전용' 작업을 자동으로 제공한다.- 여전히 일반 뷰를 사용할 때와 같이
queryset
및serializer_class
속성을 설정하고 있지만, 더 이상 두 개의 개별 클래스에 동일한 정보를 제공할 필요가 없다.
- 다음으로
SnippetList
,SnippetDetail
및SnippetHighlight
뷰 클래스를 리팩토링한다.
snippets/views.py
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import permissions
class SnippetViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
Additionally we also provide an extra `highlight` action.
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [
permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,
]
@action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, reqeust, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
- 기본 읽기 및 쓰기 작업의 전체 집합을 가져오기 위해
ModelViewSet
클래스를 사용했다. highlight
라는 사용자 지정 작업을 만들기 위해@action
데코레이터도 사용했다.- 이 데코레이터는 표준
create
/update
/delete
스타일에 맞지 않는 사용자 지정 엔드포인트를 추가하는 데 사용할 수 있다. @action
데코레이터를 사용하는 사용자 지정 작업은 기본적으로GET
요청에 응답한다.POST
요청에 응답하는 작업을 원하는 경우methods
인수를 사용할 수 있다.- 기본적으로 사용자 지정 작업의 URL은 메서드 이름 자체에 따라 다르다.
- url이 구성되는 방식을 변경하려면
url_path
를 데코레이터 키워드 인수로 포함하면 된다.
2. Binding ViewSets to URLs explicitly
- 핸들러 메서드는 URLConf를 정의할 때만 작업에 바인딩된다.
- 내부에서 무슨 일이 일어나고 있는지 보기 위해 먼저 뷰 세트를 명시적으로 생성해 보자.
snippets/urls.py
파일에서ViewSet
클래스를 구체적인 뷰 세트에 바인딩한다.
snippets/urls.py
from snippets.views import SnippetViewSet, UserViewSet, api_root
from rest_framework import renderers
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"}, renderer_classes=[renderers.StaticHTMLRenderer]
)
user_list = UserViewSet.set_view({"get": "list"})
user_detail = UserViewSet.as_view({"get": "retrieve"})
- HTTP 메서드를 각 뷰에 필요한 작업에 바인딩하여 각
ViewSet
클래스에서 여러 뷰를 만들었다. - 이제 리소스를 구체적인 뷰에 바인딩했으므로 평소와 같이 URLConf를 사용하여 뷰를 등록할 수 있다.
snippets/views.py
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"),
]
)
3. Using Routers
View
클래스가 아닌ViewSet
클래스를 사용하기 때문에 실제로 URLConf를 직접 디자인할 필요가 없다.- 리소스를 뷰와 URL에 연결하는 규칙은
Router
클래스를 사용하여 자동으로 처리할 수 있다. - 라우터에 적절한 뷰 세트를 등록하고 나머지는 라우터가 처리하도록 하면 된다.
snippets/urls.py
파일을 열어 다음과 같이 작성한다.
snippets/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
router = DefaultRouter()
router.register(r"snippets", views.SnippetViewSet)
router.register(r"users", views.UserViewSet)
urlpatterns = [
path("", include(router.urls)),
]
- 라우터에 뷰 세트를 등록하는 것은
urlpatterns
를 제공하는 것과 유사하다. - 뷰에 대한 URL 접두사와 뷰 세트 자체의 두 가지 인수를 포함한다.
DefaultRouter
클래스도 자동으로 API 루트 뷰를 생성하므로 이제views
모듈에서api_root
메서드를 삭제할 수 있다.- 이러한 뷰 세트를 사용하는 것은 뷰를 개별적으로 작성하는 것보다 덜 명시적이기 때문에 상황에 맞춰 사용한다.