일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- API
- CSS
- 알고리즘 문제
- django ORM
- java
- 파이썬
- 백준
- AWS
- 알고리즘 연습
- MAC
- 장고
- Django
- web
- Algorithm
- react
- 알고리즘 풀이
- HTML
- django widget
- es6
- js
- 알고리즘
- form
- javascript
- DRF
- Git
- 파이썬 알고리즘
- PYTHON
- django rest framework
- Baekjoon
- c++
- Today
- Total
수학과의 좌충우돌 프로그래밍
[Django] APIView, Mixins, generics APIView, ViewSet을 알아보자 본문
django 에서는 view 를 통해서 HTTP 요청을 처리합니다.
view에서 이를 처리하는 방법은 다양합니다. FBV(함수기반뷰), CBV(클래스기반뷰) 를 통해서도 API 를 만들 수 있지만 rest_framework 는 보다 쉽게, 효율적으로 만들 수 있습니다.
Serializer
[Django] django rest framework 를 위한 JSON 직렬화
저번 포스팅에서 Serializer 를 통해 Form 과 유사하게 데이터의 유효성검사 및 데이터베이스로의 저장을 구현하였습니다.
# serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
# views.py
serializer = PostSerializer(data=request.POST)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
APIView 클래스와 api_view 장식자
이번 시간에는 본격적으로 APIView 에 대해서 알아보도록 합시다.
APIView
와 api_view
는 각각 CBV와 FBV 에 대응되는 내용입니다.
두 가지 모두 뷰에 여러가지 기본 설정을 부여하게 됩니다. 이는 아래와 같고 상황에 맞춰서 이를 커스튬하여 사용하게 됩니다.
- 직렬화 클래스 지정
- renderer_classes
- default
- JSON 직렬화 : rest_framework.renderers.JSONRenderer
- HTML 페이지 직렬화 : rest_framework.renderers.TemplateHTMLRenderer
- 비직렬화 클래스 지정
- parser_classes
- default
- JSON 포맷 처리 : rest_framework.parsers.JSONParser
- FormParser : rest_framework.parsers.FormParser
- MultiPartParser : rest_framework.parsers.MultiPartParser
- 인증 클래스 지정
- authentication_classes
- default
- 세션기반인증 : rest_framework.authentication.SessionAuthentication
- HTTP basic 인증 : rest_framework.authentication.BasicAuthentication
- 사용량 제한 클래스 지정
- throttle_classes
- default
- 빈 튜플
- 권한 클래스 지정
- permission_classes
- default
- 누구라도 접근 허용 : rest_framework.permissions.AllowAny
- 요청에 따라 적절한 직렬화/비직렬화 선택
- content_negotiation_class
- 같은 URL 요청에 대해서 JSON 응답을 할 지, HTML 응답을 할 지 판단
- default
- rest_framework.negotiation.DefaultContentNegotiation
- 요청 내역에서 API 버전 정보를 탐지할 클래스 지정
- versioning_class
- 요청 URL의 HEADER에서 버전 정보를 탐지하여 맞는 버전을 호출
- default
- 버전 정보를 탐지하지 않습니다. : None
APIView
우선 APIView
부터 자세히 알아보도록 합시다.
- 위에서 말했듯이 이는 CBV 중 하나이기 때문에 하나의 URL 에 대해서만 처리를 할 수 있습니다.
- /post/ 에 대한 CBV
- get : 포스팅 목록
- post : 새 포스팅 생성
- /post/<int:pk>/ 에 대한 CBV
- get : pk 번 포스팅 내용
- put : pk번 포스팅 수정
- delete : pk번 포스팅 삭제
- /post/ 에 대한 CBV
- 요청 method 에 맞게 맴버함수를 정의하면 해당 method 로 request가 들어올 때 호출되게 됩니다.def get(self, request): pass def post(self, request): pass def put(self, request): pass def delete(self, request): pass
- 각 method 가 호출되면 위에서 봤던 설정에 맞춰 처리가 이루어집니다.
- 직렬화/비직렬화
- 인증 체크
- 사용량 제한 체크
- 권한 체크
- 요청한 버전 체크
- 실습
# models.py from django.db import models class Post(models.Model): title = models.CharField(max_length=100) content = models.TextField() create_at = models.DateTimeField(auto_now_add=True) update_at = models.DateTimeField(auto_now=True)
# serializers.py from rest_framework.serializers import ModelSerializer from .models import Post class PostSerializer(ModelSerializer): class Meta: model = Post fields = '__all__'
# views.py from rest_framework.response import Response from rest_framework.views import APIView from .models import Post from .serializers import PostSerializer # 포스팅 목록 및 새 포스팅 작성 class PostListAPIView(APIView): def get(self, request): serializer = PostSerializer(Post.objects.all(), many=True) return Response(serializer.data) def post(self, request): serializer = PostSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=201) return Response(serializer.errors, status=400) from django.shortcuts import get_object_or_404 # 포스팅 내용, 수정, 삭제 class PostDetailAPIView(APIView): def get_object(self, pk): return get_object_or_404(Post, pk=pk) def get(self, request, pk, format=None): post = self.get_object(pk) serializer = PostSerializer(post) return Response(serializer.data) def put(self, request, pk): post = self.get_object(pk) serializer = PostSerializer(post, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, pk): post = self.get_object(pk) post.delete() return Response(status=status.HTTP_204_NO_CONTENT)
from django.urls import path, include from . import views urlpatterns = [ # FBV path('post/', views.PostListAPIView.as_view()), path('post/<int:pk>/',views.PostDetailAPIView.as_view()), ]
- 각 클래스에 대해 as_view 로 라우팅을 해줍니다.
- views 에서 이들을 불러와 처리를 해주게 됩니다.
- 이에 대한 Seializer 입니다.
- 실습을 위해 간단한 Post 모델을 정의하였습니다.
@api_view 장식자
api_view는 FBV 에 대해서 사용하는 장식자 입니다.
장식자에 대한 설명은 위의 링크를 참고하시면 됩니다.
- 실습
# views.py from rest_framework.response import Response from rest_framework.views import APIView from .models import Post from .serializers import PostSerializer from rest_framework.decorators import api_view @api_view(['GET','POST']) def post_list(request): if request.method == 'GET': qs = Post.objects.all() serializer = PostSerializer(qs, many=True) return Response(serializer.data) else: serializer = PostSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=201) return Response(serializer.errors, status=400) @api_view(['GET','PUT','DELETE']) def post_detail(request, pk): post = get_object_or_404(Post, pk=pk) if request.method == 'GET': serializer = PostSerializer(post) return Response(serializer.data) elif request.method == 'PUT': serializer = PostSerializer(post, data=reqeust.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) else: post.delete() return Response(status=status.HTTP_204_NO_CONTENT)
# urls.py from django.urls import path, include from . import views urlpatterns = [ # FBV path('cbv/post/', views.post_list), path('cbv/post/<int:pk>/',views.post_detail), ]
api_view
의 첫번째 인자로 해당 함수에서 가능한 request method 를 리스트로 지정해줍니다.
Mixins 상속
APIView
는 위에서 봤듯이 각 request method 마다 직접 serializer 처리를 해주었습니다.
하지만 이러한 부분들은 많이 사용되므로 여러 serializer 에 대해서 중복이 발생합니다.
따라서 rest_framework.mixins
에서는 이러한 기능들이 미리 구현이 되어 있습니다.
- CreateModelMixin
- ListModelMixin
- RetrieveModelMixin
- UpdateModelMixin
- DestroyModelMixin
이름이 굉장히 직관적이므로 각각에 대한 자세한 설명은 생략하겠습니다.
queryset
과 serializer_class
를 지정해주기만 하면 나머지는 상속받은 Mixin
과 연결해주기만 하면 됩니다.
# views.py
from rest_framework.response import Response
from rest_framework import generics
from rest_framework import mixins
from .models import Post
from .serializers import PostSerializer
class PostListMixins(mixins.ListModelMixin, mixins.CreateModelMixin,generics.GenericAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
def get(self, request, *args, **kwargs):
return self.list(request)
def post(self, request, *args, **kwargs):
return self.create(request)
class PostDetailMixins(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.delete(request, *args, **kwargs)
이에 대한 urls 입니다.
# urls.py
from django.urls import path, include
from . import views
urlpatterns = [
# Mixin
path('mixin/post/', views.PostListMixins.as_view()),
path('mixin/post/<int:pk>/', views.PostDetailMixins.as_view()),
]
결과 화면은 위와 동일하므로 생략하도록 하겠습니다.
generics APIView
Mixin
을 상속함으로서 반복되는 내용을 많이 줄일 수 있었습니다. 하지만 여러 개를 상속해야 하다보니 가독성이 떨어집니다. 다행히도 rest_framework 에서는 저들을 상속한 새로운 클래스를 정의해놨습니다.
총 9개의 클래스로 다음과 같습니다.
generics.CreateAPIView
: 생성generics.ListAPIView
: 목록generics.RetrieveAPIView
: 조회generics.DestroyAPIView
: 삭제generics.UpdateAPIView
: 수정generics.RetrieveUpdateAPIView
: 조회/수정generics.RetrieveDestroyAPIView
: 조회/삭제generics.ListCreateAPIView
: 목록/생성generics.RetrieveUpdateDestroyAPIView
: 조회/수정/삭제
하나만 예시로 살펴보면 위에서 해주었던 Mixin 과 GenericAPIView 상속, 각 request method 에 대한 연결을 해주고 있습니다.
# rest_framework/generics.py
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
이를 통해 코드를 많이 줄일 수 있습니다.
# views.py
from rest_framework import generics
from .models import Post
from .serializers import PostSerializer
class PostListGenericAPIView(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
class PostDetailGenericAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
urls 와 결과 화면은 중복되므로 생략하도록 하겠습니다.
ViewSet
마지막으로 알아볼 ViewSet
입니다. generics APIView
를 통해서 코드를 많이 간소화 하였지만 아직 queryset 과 serializer_class 가 공통적인데도 불구하고 따로 기재해주어야합니다. 이를 한 번에 처리해주는게 바로 ViewSet
입니다.
ViewSet 은 CBV 가 아닌 헬퍼클래스로 두 가지 종류가 있습니다.
- viewsets.ReadOnlyModelViewSet : 목록 조회, 특정 레코드 조회
- viewsets.ModelViewSet : 목록 조회, 특정 레코드 생성/조회/수정/삭제
Post 모델에 대해서 ViewSet
으로 구현해보도록 하겠습니다.
# views.py
from .models import Post
from .serializers import PostSerializer
from rest_framework import viewsets
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
다음에 라우팅 하는 방법은 위와 조금 다릅니다.
Router 를 통해서 하나의 url 로 처리가 가능합니다.
#. urls.py
from django.urls import path, include
from . import views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('viewset',views.PostViewSet)
urlpatterns = [
path('',include(router.urls)),
]
http://localhost:8000/
http://localhost:8000/viewset/
http://localhost:8000/viewset/<int:pk>/
ViewSet 에 대해서는 다음 포스팅에서 좀 더 자세히 알아보도록 하겠습니다.
'웹프로그래밍 > DRF' 카테고리의 다른 글
[Django] filtering 과 Search (0) | 2019.12.29 |
---|---|
[Django] format 과 Renderer (0) | 2019.12.29 |
[Django] ViewSet 과 Router (9) | 2019.12.28 |
[Django] django rest framework 를 위한 JSON 직렬화 (0) | 2019.11.19 |
[Django] django rest framework 를 위한 JSON 기초 (0) | 2019.11.16 |