라우팅이 response에 사용할 controller을 결정한 후에
controller가 response를 이해하고 적절한 출력을 생성하는 일을 담당합니다.
- Ruby on Rails Documentation
Django REST framework를 사용하면 관련 view에 대한 논리를 ViewSet이라는 단일 클래스에 결합 할 수 있습니다. 다른 framework에서는 'Resources'나 'Controllers'와 같은 이름의 개념적으로 유사한 구현을 찾을 수 있습니다.
ViewSet class는 .get()또는 .post()와 같은 method를 제공하지 않고 대신 .list() 및 .create()와 같은 actions를 제공하는 class 기반 View입니다.
ViewSet의 method handler는 .as_view() method를 사용해서 뷰를 마무리하는 시점에만 해당 action에 바인딩 됩니다.
일반적으로 ulr conf viewset에 view를 명시적으로 등록하는 대신 ulrconf에 자동으로 결정하는 router class viewset에 등록합니다.
Example
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Response
class UserViewSet(viewsets.ViewSet):
def list(self, request):
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = User.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = UserSerializer(user)
return Response(serializer.data)
필요한 경우 다음과 같이 두 개의 개별 뷰로 바인딩할 수 있습니다.
user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})
일반적으로 이 작업은 수행하지 않지만 대신 view set을 router에 등록하고 urlconf가 자동으로 생성되도록 합니다.
from myapp.views import UserViewSet
from rest_framework.routers import defaultrouter
router = DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
urlpatterns = router.urls
자신만의 viewset을 작성하는 대신 기본 동작을 제공하는 기존 base classes를 사용하는 경우가 많습니다.
class UserViewSet(viewsets.ModelViewSet):
"""
user instances를 수정하고 보기 위한 viewset
"""
serializer_class = UserSerializer
queryset = User.objects.all()
View class보다 ViewSet을 사용하면 두 가지 이점이 있습니다.
- 반복되는 logic은 단일 class로 결합될 수 있습니다. 위의 queryset을 한 번만 지정하면 여러 view에서 사용 됩니다.
- router을 사용하면 더 이상 url 구성을 직접 연결하는 작업을 처리할 필요가 없습니다.
일반적인 View와 URL confs를 사용하면 더 명확하고 더 많은 제어가 가능해집니다.
ViewSet은 신속하게 시작하고 대규모 API가 있고 전체적으로 일관된 URL 구성을 적요하려는 경우에 유용합니다.
ViewSet actions
REST framework에 포함된 기본 라우터는 아래와 같이 create/retrieve/update/destroy action을 제공합니다
class UserViewSet(viewsets.ViewSet):
"""
빈 viewset 예시입니다. router class에서 처리할 작업입니다.
format suffixes를 사용하는 경우 'format=None' keyword를 각 action에 포함해야 합니다.
"""
def list(self, request):
pass
def create(self, request):
pass
def retrieve(self, request, pk=None):
pass
def update(self, request, pk=None):
pass
def partial_update(self, request, pk=None):
pass
def destroy(self, request, pk=None):
pass
Introspecting ViewSet actions
dispatch 중 ViewSet에서 다음 attributes를 사용할 수 있습니다.
- basename - 생성된 URL 이름에 사용할 기본입니다.
- action - 현재 작업의 이름(list, create)입니다.
- Detail - 현재 작업이 목록 보기 또는 세부정보 보기에 대해 구성되었는지 여부를 나타내는 bool 입니다.
- suffix - viewset 유형의 suffix type을 보여줍니다 detail attribute를 미러랑합니다.
- name - view 집합의 display 이름입니다. 이 인수는 suffix와 상호 배타적입니다.
- description - viewset의 개별 view에 대한 설명
위와 같은 속성을 검사하여 현재 action을 조정 할 수 있습니다.
def get_permissions(self):
"""
위 보기에 필요한 사용 권한 목록을 instance화 하고 return 합니다.
"""
if self.action == 'list':
permission_classes = [IsAuthenticated]
else:
permission_classes = [IsAdminUser]
return [permission() for permission in permission_classes]
Marking extra actions for routing
routing 해야하는 ad-hoc methods가 있으면 @action decorator을 사용해서 해당 method를 표시할 수 있습니다.
일반 action과 마찬가지로 single object나 전체 objects에 사용 가능하며 이를 나타내려면 detail argument를 True나 False로 설정합니다. 라우터는 그에 따라 URL 패턴을 구성할 것입니다. 예를 들어 DefaultRouter은 URL 패턴에 pk를 포함하도록 detail action을 구성할 것입니다.
from django.contrib.auth.models import User
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from myapp.serializers import UserSerializer, PasswordSerializer
class UserViewSet(viewsets.ModelViewSet):
"""
표준 action을 제공하는 viewset
"""
queryset = User.objects.all()
serializer_class = UserSerializer
@action(detail=True, methods=['post'])
def set_password(self, request,pk=None):
user = self.get_object()
serializer = PasswordSerializer(data=request.data)
if serailzier.is_valid():
user.set_password(serializer.validated_data['password'])
user.save()
return Response({'status': 'password set'})
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
@action(detail=False)
def recent_users(self, request):
recent_users = User.objects.all().order_by('-last_login')
page = self.paginate_queryset(recent_users)
if page is not None:
serializer = self.get_serialzier(page, many=True)
return self.get_paginated_response(serialzier.data)
serializer = self.get_serializer(recent_users, many=True)
return Response(serializer.data)
action decorator requests를 default로 GET 요청을 라우팅하지만 methods 인수를 설정해서 다른 HTTP 메서드를 허용할 수 도 있습니다.
@action(detail=True, methods=['post', 'delete'])
def unset_password(self, request, pk=None):
methods는 HTTPMethoD로 정의된 HTTP methods도 지원합니다.
from http import HTTPMethod
@action(detail=True, methods=[HTTPMethod.POST, HTTPMethod.DELETE])
def unset_password(self, request, pk=None):
decorator을 사용하면 permission_class, serializer_class, filter_backends와 같은 viewset을 재정의할 수 있습니다.
@action(detail=True, methods=['post'], permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
^users/{pk}/set_password/$ 및 ^users/{pk}/unset_password/$에서 사용할 수 있습니다.url_path와 url_name 매개 변수를 사용하여 작업의 URL segment와 reverse URL 이름을 변경합니다.
Routing additional HTTP methods for extra actions
추가 작업은 별도의 ViewSet method에 추가 HTTP methods를 매핑할 수 있습니다.
예를 들어 위의 암호 설정/해제 메서드를 단일 경로로 통합할 수 있습니다. 추가 매핑은 인수를 허용하지 않습니다.
@action(detail=True, methods=["put"], name="Change Password")
def password(self, request, pk=None):
"""Update the user's password."""
...
@password.mapping.delete
def delete_password(self, request, pk=None):
"""Delete the user's password."""
...
Reversing action URLs
action을 URL로 가져와야 하는 경우 .reverse_action() method를 사용합니다. 이건 reverse()를 위한 wrapper입니다. 편리하게 view request를 자동으로 전달하고 .basename 속성으로 url_name을 앞에 붙입니다.
basename은 ViewSet 등록 시 router에게 제공합니다. router를 사용하지 않는 경우 .as_view() method에 basename arguments를 제공해야합니다.
>>> view.reverse_action("set-password", args=["1"])
'http://localhost:8000/api/users/1/set_password'
또는 @action decorator 에서 설정한 url_name attribute을 사용할 수 있습니다.
>>> view.reverse_action(view.set_password.url_name, args=['1'])
'http://localhost:8000/api/users/1/set_password'
.reverse_action()에 대한 url_name argument는 @action decorator과 동일한 argument를 가져야합니다. 또한 이 방법을 사용하면 list와 create와 같은 기본 작업을 되돌릴 수 있습니다.
API Reference
ViewSet
ViewSet class는 APIView에서 상속됩니다. viewset의 API 정책을 제어하기 위해 permission_classes, authentication_classes와 같은 표준 속성을 사용 할 수 있습니다.
ViewSet class는 action 구현을 제공하지 않습니다. ViewSet class를 사용할면 class를 override하고 action 구현을 정의해야합니다.
GenericViewSet
GenericViewSet class는 GenericAPIView에서 상속되며 기본 get_object, get_queryset method 및 기타 일반 view 기본 동작을 제공하지만 어떠한 action도 포함하지 않습니다.
GenericViewSet class를 사용하려면 class의 override가 필요하고 mixxin class를 사용하거나 action을 정의해야합니다.
ModelViewSet
ModelViewSet class는 GenericAPIView를 상속되며 다양한 혼합 class action을 가져 다양한 작업 구현을 포함합니다.
ModelViewSet class에서 제공하는 action은 .list(), .retrieve(), .create(), .update(), .partial_update() 및 destroy() 입니다.
Example
ModelViewSet은 GenericAPIView를 확장하므로 queryset 및 serializer_class 속성을 제공해야 합니다.
class AccountViewSet(viewsets.ModelViewSet):
"""
계정을 보고 편집하기 위한 간단한 viewset
"""
queryset = Account.objects.all()
serializer_class = AccountSerializer
permission_classes = [IsAccountAdminOrReadOnly]
GenericAPIView에서 제공하는 표준 속성이나 메서드 재정의를 사용할 수 있습니다. 예를 들어, 작동해야 하는 queryset을 dynamically 결정하려면 ViewSet을 사용하려면 다음과 같이 할 수 있습니다.
class AccountViewSet(viewsets.ModelViewSet):
"""
계정을 보고 편집하기 위한 간단한 ViewSet 사용자와 연결됩니다
"""
serializer_class = AccountSerializer
permission_classes = [IsAccountAdminOrReadOnly]
def get_queryset(self):
return self.request.user.accounts.all()
ViewSet에서 queryset을 제거하면 연결된 라우터가 model의 basename을 자동으로 derive 할 수 없으므로 라우터 등록의 일부로 basename kwarg를 지정해야 한다.
또한 이 class는 기본적으로 create/list/retrieve/update/destroy action을 제공하지만 standard permission classes를 사용해 가능한 작업을 제한할 수 있습니다.
ReadOnlyModelViewSet
ReadOnlyModelViewSet class는 GenericAPIView를 상속합니다. ModelViewSet과 마찬가지로 다양한 작업에 대한 구현도 포함하지만 'read-only' action인 .list()와 .retrieve()만 제공합니다.
Example
ModelViewSet과 마찬가지로 최소한의 queryset 및 serializer_class attributes를 제공해야 합니다.
class AccountViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Account.objects.all()
serializer_class = AccountSerializer
ModelViewSet과 마찬가지로 GenericAPIVIew에서 사용할 수 있는 standard attribute와 method를 override 할 수 있습니다.
Custom ViewSet base classes
전체 ModelViewSet actions이 없거나 다른 방식으로 action을 사용자가 정의해야 하는 ViewSet class를 제공하는 방법
Example
create, list, retrieve를 제공하고 GenericViewSet을 상속해서 필요한 작업을 mixin하려면 다음처럼 하세요
from rest_framework import mixins
class CreateListRetrieveViewSet(mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
'Django > restframework' 카테고리의 다른 글
Restframework JWT 설정 (0) | 2024.01.29 |
---|---|
Routers (0) | 2024.01.23 |
Generic views (0) | 2024.01.18 |
DRF docs API Guide Class-based Views (1) | 2024.01.15 |
DRF docs API Guide Responses (0) | 2024.01.12 |