일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 파이썬 알고리즘
- web
- js
- 알고리즘 문제
- PYTHON
- java
- API
- Django
- HTML
- MAC
- react
- django widget
- Algorithm
- DRF
- 파이썬
- form
- AWS
- 알고리즘
- django ORM
- 알고리즘 연습
- CSS
- Git
- c++
- Baekjoon
- django rest framework
- es6
- 장고
- 백준
- 알고리즘 풀이
- javascript
- Today
- Total
수학과의 좌충우돌 프로그래밍
[Django] ViewSet 과 Router 본문
Django-APIView-Mixins-genericsAPIView-ViewSet을-알아보자
저번 포스팅에서 ViewSet
에 대해서 간단히 알아보았습니다. 이번에는 좀 더 자세히 알아보도록 하겠습니다.
ViewSet
저번 포스팅에서도 언급했지만 ViewSet 은 다른 것들과 좀 달랐습니다.
일반적인 CBV 가 아니기 때문에 as_view 를 통해서 뷰를 만들지 않고 router를 사용했습니다.
as_view 를 사용하지 않는 이유는 ViewSet 은 하나의 뷰가 아닌 set, 여러 개의 뷰를 만들 수 있는 확장된 CBV이기 때문입니다.
사실 ViewSet 도 as_view를 사용하여 각각의 뷰를 만들어줄 수 있습니다.
.as_view({
'http method': '함수'
})
ViewSet 은 두 가지 종류로 이루어져 있습니다. 두 종류 모두 자체적인 구현은 없고 Mixin 을 적절히 상속받아 여러 기능을 수행하게 됩니다.
-
viewsets.ReadOnlyModelViewSet
-
목록
- mixins.ListModelMixin : list() 함수
-
특정 레코드
- mixins.RetrieveModelMixin : retrieve() 함수
-
-
viewsets.ModelViewSet
-
목록
- mixins.ListModelMixin : list() 함수
-
특정 레코드
- mixins.RetrieveModelMixin : retrieve() 함수
-
레코드 생성
- mixins.CreateModelMixin : create() 함수
-
레코드 수정
- mixins.UpdateModelMixin : update() 함수, partial_update() 함수
partial_update()
부분적인 필드값만 받아 수정이 가능하며 request method 중 Fetch 와 대응된다.
-
레코드 삭제
- mixins.DestroyModelMixin : destroy() 함수
-
ModelViewSet
이 ReadOnlyModelViewSet
의 기능들을 함축하므로 ModelViewSet
에 대한 간단한 예시를 살펴보겠습니다.
우선 Post
모델을 정의해주겠습니다.
# models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
is_public = models.BooleanField(default=False)
create_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
이에 대해서 Serializer 를 만들어주고
# Serializers.py
from rest_framework.serializers import ModelSerializer
from .models import Post
class PostSerializer(ModelSerializer):
class Meta:
model = Post
fields = '__all__'
ViewSet 을 정의해줍니다. 위에서 알아봤던 ModelViewSet
의 모든 기능을 다 연결시켜주었습니다.
# views.py
from django.shortcuts import render
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet
from .models import Post
from .serializers import PostSerializer
class PostViewSet(ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
post_list = PostViewSet.as_view({
'get': 'list',
'post': 'create',
})
post_detail = PostViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy',
})
마지막으로 url 만 연결해주면 아래와 같은 결과 화면을 볼 수 있습니다.
# urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('post/', views.post_list),
path('post/<int:pk>/', views.post_detail),
]
Router
이 역시 저번 포스팅에서 봤듯이 URL 매핑을 편리하게 할 수 있습니다. 기존에는 as_view 를 통해 각 request method 마다 대응되는 함수를 연결시켜주었다면 router 는 이를 알아서 연결시켜줍니다.
디폴트 매핑은 위에서 본 것과 동일합니다.
-
list route
-
url : /prefix/
-
name : {model name}-list , 단 model name 은 소문자입니다.
'get': 'list' 'post': 'create'
-
-
detail route
-
url : /prefix/pk/
-
name : {model name}-detail
'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy',
-
위의 urls 를 아래와 같이 수정하였습니다. 이 때 prefix
자리에는 post
가 쓰였고 이에 따라 url이 결정됩니다.
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
router.register(r'post',views.PostViewSet)
urlpatterns = [
path('',include(router.urls)),
]
더 이상 as_view
를 통해 단일 뷰를 뽑아낼 필요가 없어졌습니다.
# views.py
from django.shortcuts import render
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet
from .models import Post
from .serializers import PostSerializer
class PostViewSet(ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
다음과 같이 Router
를 사용하게 되면 Api Root 를 제공해줍니다. 해당 app 에 대한 root url 로 갈 경우 아래 이미지와 같이 Router 에 등록된 ViewSet을 확인 할 수 있습니다.
ViewSet 더 알아보기
디폴트 매핑의 경우, list route 에 대해서 2개, detail route 에 대해서 4개에 대해서 매핑을 해주게 됩니다. 하지만 실제로는 6개보다 더 많은 경우가 비일비재합니다. 따라서 추가적으로 매핑을 하는 방법에 대해서 알아보도록 하겠습니다.
추가적으로 매핑하는 방법은 간단합니다. ViewSet
의 맴버함수로 구현한 후 decorator 를 붙여주면 됩니다. 이 때 URL 은 Router가 알아서 결정해줍니다.
decorator action
매핑하기 위해서 action decorator
를 사용하는데 이에 대해서 알아보도록 하겠습니다.
-
import 경로
from rest_framework.decorators import action
-
detail
action
은 첫번째 인자로 detail 값을 받습니다. Boolean 으로서 True 일 경우, pk 값을 지정해줘야하는 경우에 사용하고 False일 경우, 목록 단위로 적용하게 됩니다. -
methods
request method 를 지정해줄 수 있습니다. 디폴트 값은 get 으로 자세한 사용방법은 아래 예시를 통해 보겠습니다.
이 때 detail 값에 따라 Router가 URL 을 결정하는 방법이 다릅니다.
-
detail=True
- url : /prefix/{pk}/{function name}/
- name : {model name}-{function name}
-
detail=False
- url : /prefix/{function name}/
- name : {model name}-{function name}
이 때 모든 이름은 소문자이며, function name의 언더바(_)는 하이픈(-) 으로 교체됩니다.
is_public
값이 True 인 레코드만 필터링하는 public_list
와 특정 레코드의 is_public
을 True로 바꿔주는 set_public
을 정의하였습니다.
# views.py
from django.shortcuts import render
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Post
from .serializers import PostSerializer
class PostViewSet(ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
# url : post/public_list/
@action(detail=False)
def public_list(self, request):
qs = self.queryset.filter(is_public=True)
serializer = self.get_serializer(qs, many=True)
return Response(serializer.data)
# url : post/{pk}/set_public/
@action(detail=True, methods=['patch'])
def set_public(self, request, pk):
instance = self.get_object()
instance.is_public = True
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
'웹프로그래밍 > DRF' 카테고리의 다른 글
[Django] filtering 과 Search (0) | 2019.12.29 |
---|---|
[Django] format 과 Renderer (0) | 2019.12.29 |
[Django] APIView, Mixins, generics APIView, ViewSet을 알아보자 (15) | 2019.12.27 |
[Django] django rest framework 를 위한 JSON 직렬화 (0) | 2019.11.19 |
[Django] django rest framework 를 위한 JSON 기초 (0) | 2019.11.16 |