[drf | agiliq] More views and viewsets
More views and viewsets
A better URL structure
현재 API endpoints
/polls/
and/polls/<pk>/
/choices/
/vote/
위 기존 API URLs를 만들었지만 더 직관적이고 중첩된 소스코드를 통해서 리디자인할텐데요.
/polls/
과/polls/<pk>
/polls/<pk>/choices/
/polls/<pk>/choices/<choice_pk>/vote/
Changing the views
ChoiceList
및 CreateVote
를 바꿔볼게요. /polls/
와/polls/<pk>
변경되지 않았거든요.
from rest_framework import generics
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from .models import Poll, Choice
from .serializers import PollSerializer, ChoiceSerializer, VoteSerializer
# ...
# PollList and PollDetail views
class ChoiceList(generics.ListCreateAPIView):
def get_queryset(self):
queryset = Choice.objects.filter(poll_id=self.kwargs["pk"])
return queryset
serializer_class = ChoiceSerializer
class CreateVote(APIView):
serializer_class = VoteSerializer
def post(self, request, pk, choice_pk):
voted_by = request.data.get("voted_by")
data = {'choice': choice_pk, 'poll': pk, 'voted_by': voted_by}
serializer = VoteSerializer(data=data)
if serializer.is_valid():
vote = serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
nested구조로 urls.py를 바꿀게요.
urlpatterns = [
path("polls/<int:pk>/choices/", ChoiceList.as_view(), name="choice_list"),
path("polls/<int:pk>/choices/<int:choice_pk>/vote/", CreateVote.as_view(), name="create_vote"),
]
GET을 수행하여 변경 사항을 볼 수 있습니다 http://localhost:8000/polls/1/choices/
[
{
"id": 1,
"votes": [],
"choice_text": "Flask",
"poll": 1
},
{
"id": 2,
"votes": [
],
"choice_text": "Django",
"poll": 1
}
]
http://localhost:8000/polls/1/choices/2/vote/data
로 POST를 수행하여 투표 1 중 선택 2에 투표 할 수 있습니다 . {"voted_by": 1}
{
"id": 2,
"choice": 2,
"poll": 1,
"voted_by": 1
}
ChoiceList
로 가볼게요.
# urls.py
#...
urlpatterns = [
# ...
path("polls/<int:pk>/choices/", ChoiceList.as_view(), name="choice_list"),
]
# apiviews.py
# ...
class ChoiceList(generics.ListCreateAPIView):
def get_queryset(self):
queryset = Choice.objects.filter(poll_id=self.kwargs["pk"])
return queryset
serializer_class = ChoiceSerializer
urls에서 pk
를 ChoiceList
에 전달해줘요.
get_queryset
메서드를 오버라이드 해줘서 choices에대한 filter를 poll_id
로 하게되요.
그리고 나머지는 DRF에서 다루게 하고요.
그리고 CreateVote
의 경우는,
# urls.py
#...
urlpatterns = [
# ...
path("polls/<int:pk>/choices/<int:choice_pk>/vote/", CreateVote.as_view(), name="create_vote"),
]
# apiviews.py
# ...
class CreateVote(APIView):
def post(self, request, pk, choice_pk):
voted_by = request.data.get("voted_by")
data = {'choice': choice_pk, 'poll': pk, 'voted_by': voted_by}
serializer = VoteSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
poll id
== pk, choice id
를 전달하게되는데요. 그리고 subclass로 generic
을 사용하지 않고 APIView
를 사용하는데 그 이유는 커스터마이징에 초점을 뒀기 때문이에요.
초기 시리얼라이저에 데이터를 직접 넣었던 APIView
에 더 유사합니다. 그리고 is_valid()
를 통해서 데이터 유효성에 따라 성공시 데이터 반환과 오류시 에러 반환이 분기되게 되요.
Introducing Viewsets and Routers
지금 소스 코드 역시 괜찮지만 더욱더 효율적인 리팩토링이 가능해요.
현재 잘보면 /polls/
, /polls/<pk>/
엔드포인트는 동일한 queryset
, serializer_class
를 받고 있어요.
요것들을 viewset
하나로 그룹시킬 수 있어요. 그리고 urls
에서는 router
를 이용해서 연결시킬 수 있어요.
# urls.py
# ...
from rest_framework.routers import DefaultRouter
from .apiviews import PollViewSet
router = DefaultRouter()
router.register('polls', PollViewSet, basename='polls')
urlpatterns = [
# ...
]
urlpatterns += router.urls
# apiviews.py
# ...
from rest_framework import viewsets
from .models import Poll, Choice
from .serializers import PollSerializer, ChoiceSerializer, VoteSerializer
class PollViewSet(viewsets.ModelViewSet):
queryset = Poll.objects.all()
serializer_class = PollSerializer
URL이나 응답에는 전혀 변경이 없습니다. /polls/
, /polls/<pk>/
에서 GET 수행을 통해 확인할 수 있습니다.
Choosing the base class to use
지금까지 API 뷰를 빌드하는 4 가지 방법을 보았습니다.
- 순수한 장고 뷰
APIView
하위 클래스generics.*
하위 클래스viewsets.ModelViewSet
그렇다면 언제 어떤 것을 사용해야 할까요?
viewsets.ModelViewSet
은 대부분의 모델CRUD
에 대한 작업을 일임 할때generics.*
viewset
낮은 단계로 본인이 허용하길 원하는 몇가지 모델에 국한 할때APIView
본인이 자유롭게 커스터마이징 하길 원할때
Next steps
다음 장에서는 API에 액세스 제어를 추가하는 방법을 살펴 보겠습니다.
Author And Source
이 문제에 관하여([drf | agiliq] More views and viewsets), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@hyeseong-dev/drf-agiliq-More-views-and-viewsets저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)