Django REST framework 1 Serializer, ApiView
03 Sep 2021 | 입문 위코드 TIL위코드 22기 분들이 한 달동안 작성한 채용 관리 사이트를 drf로 리팩토링하라는 업무를 받음으로서 Django REST framework, 장고 레스트 프레임워크를 처음 접하게 됐다. 코드를 읽어보고 공식 문서와 블로그를 둘러보면서 알아보려고 하다가 모르겠어서 위코드의 멘토님께 강의를 추천받아서 들었더니 첫 기본 개념이 좀 잡혔다.
동기의 말에 따르면 학원에서 만들었던 퓨어장고는 레고와 같고 DRF는 철근과 같다고 한다. 멘토님의 말에 따르면 DRF를 사용하면 더 쉽고 빠르게 기능을 구현할 수 있고 틀이 정해져있어서 대부분의 개발자가 같은 형식을 공유하게 되고 에러가 날 여지가 더 적다고 한다.
코드를 뜯어보면 상속과 클래스를 통해 장고에서 만들어놓은 기본 기능을 가져다씀으로써 라우팅과 같은 기본 기능보다 상태별 모델링이나 API의 상호작용에 더 집중할 수 있도록 하는 것 같다.
Django Rest Framework
웹에서 모바일로 사용환경이 변화함에 따라서 HTML뿐만 아니라 JSON으로 데이터를 처리하는 것이 필요해졌다.
REST(representational state transfer)는 HTTP의 URL과 HTTP method(GET, POST, PUT, DELETE)를 사용하여 API 사용 가독성을 높인 구조화된 시스템 아키텍쳐(프레임워크)이고
REST의 설계 원칙으로는 서버와 클라이언트의 존재, Stateless, Uniform Interface등 다양한 조건이 존재하지만 현대 HTTP통신에서는 JSON 형식으로 데이터를 주고받기 때문에 self-descriptive의 조건을 만족하지 못해서 REST의 의도를 벗어난다고 한다.
API(Application Program Interface)는 request, response로 오가는 구조화된 데이터를 의미하고 클라이언트와 서버 간의 메신저, 매개체 역할을 통해 서로간의 데이터를 특정 형식에 맞게 전달하는 역할을 한다.
RESTful API는 이러한 RESTful의 개념과 API를 합쳐서 REST 설계 원칙을 따르는 API를 의미하며, 우리는 RESTful API를 통해 HTTP로 CRUD 등의 기능을 수행하는 API를 개발할 수 있다.
Django REST framework(이하 DRF)는 장고안에서 Restful API 서버를 쉽게 구축할 수 있도록 도와주는 오픈소스 라이브러리이다.
추천해주신 강의를 보고 개념을 이해하고 여러가지 블로그를 보고 정리했다.
내가 여태까지 이해한 바로 DRF의 주요 기능에는 다음과 같은 것들이 있다.
- Serializer : data를 json으로 직렬화해준다. (API 디버깅을 쉽게 만들어주며 코드를 정리해서 보안 이슈를 해결하기도 하며 validation도 검증해준다.)
- ModelSerializer : 모델에 serializer를 적용할 때 사용한다.
- Api View : View를 기반으로 Restful API를 더 쉽게 작성할 수 있게 해준다. 함수기반 Function based View, 클래스기반 Class based View가 있다.
- GenericAPIView, Mixins : CRUD기능이 미리 만들어져있어서 가져다 쓸수 있다.
- ViewSet : Class Based View를 더 간결하고 쉽게 사용하지 위한 추상클래스를 이용해 확장된 버전이다.
뷰셋은 유용한 추상화를 제공하며 일관된 API 접근, 코드 작성의 최소화, 일일이 URL conf를 작성하는 대신 상호작용과 표현에 더 집중할 수 있도록 도와주지만 마치 클래스 기반 뷰와 함수 기반 뷰를 선택할 때와 비슷한 트레이드 오프가 있으며, 직접 뷰를 작성할 때보다 덜 명료하다. 그러니 뷰셋이 항상 좋은 선택이 아니라 상황에 따라 판단을 해야한다. - drf 공식 문서
Serializer
data를 json으로 직렬화 해준다. 직렬화에 대한 자세한 설명 반대로 parser는 json을 data로 다시 만들어준다.
ModelSerializer
모델의 인스턴스들을 serialize하려면 아래와 같이 길게 작성해야하는데 Model Serializer를 이용하면 이렇게 짧게 작성할 수 있다.
ApiView
django 에서는 view 를 통해서 HTTP 요청을 처리하는데 Api view는 RESTful한 API를 만들 때 사용하는 것으로
- 클래스를 기반으로 사용하면 뷰 클래스를 APIView를 사용하여 클래스를 만들고 예시: class PostListAPIView(APIView)
- 함수를 기반으로 사용하면 @api_view([‘GET’,’POST’])이런 식으로 함수 위에 데코레이터를 사용하는 방식으로 쓸 수 있다.
1번 클래스기반 뷰
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)
2번 함수기반 뷰
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)