2022. 7. 13. 14:24ㆍ강의 정리/Django REST Framework
REST의 규칙에 우리는 맞춰 코딩을 하고있음을 인지하는게 매우 중요하다.
ViewSet은 REST의 반복적인 코딩 패턴을 줄여준다.
우리는 일반적으로 REST API를 구현할 때 모델을 기준으로 List와 Detail URL에 대한 API를 구현한다.
이 때 List API는 GET, POST 메소드를 구현하며 Detail API 는 GET, PUT, DELETE메소드를 구현한다.
이 각 2개의 URL별로 모두 5개의 메소드 구현을 REST의 반복되는 일관된 패턴으로 볼 수도 있을 것이다.
DRF에서는 모델을 기준으로 하나의 ViewSet으로 묶어서 위에서 언급한 패턴을 한방에 구현할 수 있다. ViewSet에 queryset과 serializer를 지정만 해주고 Router클래스로 url에 추가만 해주면 된다.
ViewSet
단일 리소스에서 관련있는 View들을 단일 클래스에서 제공
- 위의 말을 쉽게 설명 하자면 RESST API는 일반적으로 2개의 URL이 필요하다.
- list/create, detail/update/partial_update/delete로 나눠지는 2개의 클래스 기반 뷰가 필요하다.
- 그러나 ViewSet에서는 2개의 구현을 단일 클래스에서 지원해준다.
# https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/
from rest_framework import viewsets
from rest_framework.response import Response
class PostViewSet(viewsets.ViewSet):
def list(self, request): # list
queryset = Post.objects.all()
serializer = PostSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk): # detail
queryset = Post.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = PostSerializer(user)
return Response(serializer.data)
# https://www.django-rest-framework.org/api-guide/routers/
router = DefaultRouter()
router.register('post', PostViewSet, basename='post') # 2개의 URL을 만들어준다.
router.urls
# urls에 다음과 같이 추가한다. -> path('', include(router.urls)
- 위는 메소드들을 직접 구현한 것이고, ModelViewSet을 상속받으면 메소드가 전부 구현이 되어있다.
# https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/
from rest_framework import ModelViewSet
from rest_framework.response import Response
class PostViewSet(ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
- ModelViewSet에서는 쿼리셋과 Serializer만 적으면 된다. // 기본 메소드가 모두 구현되어있기에
ModelViewSet
2가지 ModelViewSet이 존재한다.
Viewsets.ReadOnlyModelViewSet -> GET 요청(조회)에만 반응하는 ModelViewSet
- list 지원 → 1개의 URL
- detail 지원 → 1개의 URL
Viewsets.ModelViewSet -> GET뿐만 아니라 모든 요청에 반응하는 ModelViewSet
- list/create 지원 → 1개의 URL
- detail/update/partial_update/delete 지원 → 1개의 URL
URL Patterns에 매핑
from rest_framework import viewsets
class PostViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
필요한 method만 뽑아서 개별 View를 만들수도있고
# PostViewSet으로부터 필요한것만 뽑아 쓰기
#'입력받은 mehtod' : '출력할 함수'
post_list = PostViewSet.as_view({
'get': 'list',
})
post_detail = PostViewSet.as_view({
'get': 'retrieve',
})
# urls에 하나하나 직접 path를 다 써야한다.
또 다른 예시
message_list = MessageViewSet.as_view({
'get': 'list',
'post': 'create',
})
message_detail = MessageViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
})
urlpatterns = [
path('/message', message_list),
path('/message/<int:pk>', message_detail),
]
Router 통해서 일괄적으로 urlpatterns에 등록할 수 있다.
# Router를 통해 일괄등록을 하면 추가 기능이 있다.
# http://localhost:8000/post/1.api, http://localhost:8000/post/1.json 등의 포맷 인자(api, json)를 추가로 url_patterns에 추가된다. 포맷 인자로 요청 시 요청에 따라 json, api응답이 온다. 아래 Router 참조
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('post', views.PostViewSet) # 'post': URL에 사용될 리소스 이름이다. 보통은 모델명 사용
urlpatterns = [
path('', include(router.urls)),
]
- http://localhost:8000/post/1.api, http://localhost:8000/post/1.json 등의 포맷 인자(api, json)를 추가로 url_patterns에 추가된다. 포맷 인자로 요청 시 요청에 따라 json, api(DRF html)응답이 온다.
Router
ReadOnlyModelViewSet과 ModelViewSet에 대해서 동일한 URL Pattern 리스트가 생성된다.
- list route
- detaul route
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('post', views.PostViewSet) # 'post'가 url의 prefix가 된다.
urlpatterns = [
path('', include(router.urls)),
]
# 아래 URL 패턴들은 위 router 추가시 자동으로 등록되는 주소들이다.
[
<URLPattern '^post/$' [name='post-list']>,
<URLPattern '^post\.(?P<format>[a-z0-9]+)/?$' [name='post-list']>, # 주의) 구분자 "_"가 아니라 "-"이다.
<URLPattern '^post/(?P<pk>[^/.]+)/$' [name='post-detail']>,
<URLPattern '^post/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='post-detail']>,
<URLPattern '^$' [name='api-root']>,
<URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>
# api-root : 현 Router에 등록된 ViewSet내역을 조회
]
ViewSet에 새로운 EndPoint 추가하기
EndPoint란
- 특정 URL을 호출하게 되면, 생성되고
- 하나의 endpoint 는 보통 JSON 포맷으로 된 데이터와 동작 가능한 HTTP method 정보를 가지고 있다.
from rest_framework.decorators import action
class PostModelViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
"""
URL Reverse 명: basename-함수명 (언더바는 하이픈으로 변경)
즉, post-public이 된다.
"""
@action(detail=False, methods=['GET']) # 특정 포스팅이 아니므로 detail=False
def public(self, request):
qs = self.get_queryset().filter(is_public=True)
serializer = self.get_serializer(qs, many=True)
return Response(serializer.data)
@action(detail=True, methods=['PATCH']) # 특정 포스팅이므로 detail=True
def set_public(self, request, pk): # public으로 변경하는 api
instance = self.get_object()
instance.is_public = True
instance.save() # 또는 instance.save(update_fields=['is_public'])
serializer = self.get_serializer(instance)
return Response(serializer.data)
# @action의 detail인자에 따라서 list URL을 탈건지, detail URL을 탈건지 결정된다.
- get_serializer(쿼리셋, many=True)에서 many=True는 여러 객체를 가져온다는 것을 의미한다.
Router 사용시 API를 반환하는 함수 이름으로 자동으로 endpoints가 생성된다.
위 코드를 통해 자동으로 생성된 URL Patterns 리스트
[
# ...
<URLPattern '^post/public/$' [name='post-public']>,
<URLPattern '^post/public\.(?P<format>[a-z0-9]+)/?$' [name='post-public']>,
# ...
<URLPattern '^post/(?P<pk>[^/.]+)/set_public/$' [name='post-set-public']>,
<URLPattern '^post/(?P<pk>[^/.]+)/set_public\.(?P<format>[a-z0-9]+)/?$' [name='post-set-public']>,
# ...
]
'강의 정리 > Django REST Framework' 카테고리의 다른 글
DRF Serializer를 통한 유효성 검사 및 저장 (0) | 2022.07.14 |
---|---|
From과 Serializer 관점에서 DRF 비교 (0) | 2022.07.13 |
DRF mixins 상속을 통한 APIView (0) | 2022.07.12 |
DRF로 APIView, Json 응답뷰 만들기 (0) | 2022.07.11 |
Django JSON 직렬화 (0) | 2022.03.22 |