일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- django rest framework
- 테스나
- 덕우전자
- 내돈내산
- RFHIC
- 센트랄모텍
- 라이자의 아틀리에
- 삼성 사운드바
- Algorithm
- 천랩
- 야생의 숨결
- it takes two
- 빈센조
- viewset
- 현대차
- 에스티팜
- SW Certificate
- 삼성큐브냉장고
- Baekjoon
- NKE
- 레오폴드FC660C
- 닌텐도스위치
- U32H850
- 등급 검정
- LG화학
- 삼성전자
- 에이비프로바이오
- 페르소나5로열
- tsla
- 고바이오랩
- Today
- Total
HJ Works
[Django REST Framework] ViewSet 이용과 Customize 본문
Django를 이용한 웹 개발시 Function Based View 또는 Class Based View를 복합적으로 사용 가능하다. Django 서비스 개발이 성숙하고, 구조적인 설계를 지향하다 보면 CBV를 쓰게 된다.
Django REST Framework 를 사용하면, 여기서 한단계 더 진화한 ViewSet 을 쓰게 된다. ViewSet을 이용하면 한개의 CBV가 여러개의 인터페이스를 자동으로 만들어준다.
매우 간단한 예로 다음과 같은 코드를 만들 수 있다.
기본적인 사용법
views.py
class SimpleViewSet(viewsets.ViewSet):
def list(self, request):
queryset = myQuerySet()
serializer = SimpleSerializer(queryset, many=True)
return Response(serializer.data)
def retrive(self, request, pk=None):
queryset = myQuerySet()
obj = get_object_or_404(Object, pk=pk)
serializer = SimpleSerializer(queryset, many=True)
return Response(serializer.data)
# 이 외에도 create(self), update(self), destroy(self) 등을 override 가능하다.
urls.py
from rest_framework.routers import DefaultRouter
from .views import SimpleViewSet
router = DefaultRouter()
router.register('simple', SimpleViewSet)
urlpatterns = router.get_urls()
위와 같이 url을 완성하면, 별도의 URL conf 설정을 하지 않아도 다음과 같은 표준 URL interface가 작성된다.
즉, DRF의 ViewSet과 Router를 조합하여 CRUD에 필요한 대부분의 URL이 자동으로 생성되는 것이다.
simple/ simple/?P<pk> |
추가 URL 설정하기
또한, abstract method 외에도 직접 method 추가를 할 수 있다.
views.py
class SimpleViewSet(viewsets.ViewSet):
...
@action
def customize(self):
queryset = myCustomQuery()
return Response(Serialize(queryset).data)
simple/ simple/?P<pk> simple/customize |
Model 있는 ViewSet 작성하기
사실 ViewSet이 진정한 능력을 발휘할 때는 Model Based View를 만들 때이다.
GenericViewSet과 Mixin을 적절히 조합해서, 대부분의 method를 작성하지 않아도 충분한 작업을 할 수 있다.
models.py
class SimpleModel(models.Model):
foo = models.CharField()
bar = models.Integerfield()
views.py
from rest_framework viewsets, mixins
class SimpleModelViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
queryset = mySimpleQuerySet()
serializer_class = mySimpleSerializer
urls.py
from rest_framework.routers import DefaultRouter
from .views import SimpleModelViewSet
router = DefaultRouter()
router.register('simple', SimpleModelViewSet)
urlpatterns = router.get_urls()
위와 같이, 기존의 DRF View를 쓸 때와 마찬가지로 queryset, serializer_class를 지정해 두면, 이 내용이 URL에 포함된다.
만약 viewsets.ModelViewSet을 이용한다면, 해당 Model 의 모든 작업 (CRUD) 이 가능하다.
하지만, 해당 View 목적에 따라 GenericViewSet 과 일부 Mixin만을 가져올 수 있다.
위의 사례는 viewsets.ReadOnlyModelViewSet과 동일한 역할을 하며,
이 경우 URL이 아래와 같이 되나 GET/HTTP만 이용하게 된다.
simple/ simple/(?P<pk>) ... |
따라서, 위의 SimpleModelViewSet에 CreateModelMixin 을 추가하면, post 데이터를 기반으로 create 작업을 할 수 있게 되는 것이다.
조금 더 튜닝하기
ModelViewSet에서 PK를 조작하기
Model을 이용하는 GenericViewSet 과 ModelMixin의 경우, 연결된 DB의 PK를 자동으로 가져오게 된다.
그래서 위와 같이 pk가 붙게 된다. 예를 들면 다음과 같이 된다.
https://my-service.com/api/simple # 이 URL은 simple DB 전체를 가져온다. https://my-service.com/api/simple/1 # 이 URL은 simple DB 중 PK 1에 해당하는 값을 가져온다. |
별도 설정을 하지 않으면 pk가 제일 뒤에 URL suffix로 붙는다. pk가 아닌 value를 쓰고 싶거나, 이 위치를 바꿀 수 있다.
urls.py
from rest_framework.routers import DefaultRouter
from .views import SimpleModelViewSet
router = DefaultRouter()
router.register(r'simple/(?P<non_pk_value>[regex]', SimpleModelViewSet)
urlpatterns = router.get_urls()
위 router는 non_pk_value를 이용해서 filter된 결과를 가져오려고 한다.
다만, 이 경우 RetrieveMixin
이 활성화된다. 결국 non_pk_value 가 해당 테이블에서 유니크하지 않다면 get_object()
가 multiple object returns
예외를 일으킬 것이라서 유의하여야 한다.
views.py
from rest_framework viewsets, mixins
class SimpleModelViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
serializer_class = mySimpleSerializer
def get_queryset(self):
normal_value = self.kwargs.get('non_pk_value')
qs = Simple.objects.filter(value=normal_value)
return qs
이런 형태로 non_pk_value를 queryset에서 설정하게 된다. 다만, 여기서 qs는 1개만 리턴한다고 전제되어야 한다.(위의 get_object 가 에러를 일으키게 된다.)