지금까지는 함수형 views
를 썼는데 앞으로는 Class형 views
를 작성한다.
# articles/views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.generics import get_object_or_404
from articles.models import Article
from articles.serializers import ArticleSerializer
# 함수형 뷰
@api_view(['GET', 'POST'])
def articleAPI(request):
if request.method == 'GET':
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST': # 디시리얼라이즈
serializer = ArticleSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
# print(serializer.data)
# print(request.data['title'])
return Response(serializer.data, status=status.HTTP_201_CREATED) # 완성된 데이터를 보내준다.
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# 개발 단계에선 편리하지만 front에 표시하는 건 보안상 좋지 않다.
@api_view(['GET', 'PUT', 'DELETE'])
def articleDetailAPI(request, article_id):
if request.method == 'GET':
# return Response(article) 이렇게는 할 수 없고
# article = Article.objects.get(id=article_id) # 1004를 저장
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article)
return Response(serializer.data)
elif request.method == 'PUT':
# 위 상세페이지처럼, 복사해서 가져와서 수정을 해줘야 한다.
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article, data=request.data)
# (원래data:읽기, 나중에들어온data) 앞의data를 뒤data로 바꾸어주는 것.
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
elif request.method == 'DELETE':
article = get_object_or_404(Article, id=article_id)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
https://www.django-rest-framework.org/tutorial/3-class-based-views/ 에서 복붙해서 시작해도 괜찮다.
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.views import APIView # 추기
from rest_framework.generics import get_object_or_404
from articles.models import Article
from articles.serializers import ArticleSerializer
from drf_yasg.utils import swagger_auto_schema # 추가
class ArticleList(APIView):
def get(self, request, format=None):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
@swagger_auto_schema(request_body=ArticleSerializer)
def post(self, request, format=None):
serializer = ArticleSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ArticleDetail(APIView):
def get(self, request, article_id, format=None):
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article)
return Response(serializer.data)
def put(self, request, article_id, format=None):
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, article_id, format=None):
article = get_object_or_404(Article, id=article_id)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
generic class-based views를 쓰면 기본 기능은 빨리 만들 수 있다. 토이프로젝트 등 빨리 만들어 테스트할 때는 mixins 등을 적극적으로 사용해도 되지만 커스터마이징이 어렵고 trade-off가 있다.
프로젝트는 generic은 사용하지 않고 위와 같이 (APIView)를 상속 받아 사용하는 Class Based Views(CBV)를 사용한다.
# articles/views.py
...
from drf_yasg.utils import swagger_auto_schema # 추가
class ArticleList(APIView):
def get(self, request, format=None):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
# 추가 (ArticleSerializer 명세에 맞춰 전송할 것)
@swagger_auto_schema(request_body=ArticleSerializer)
def post(self, request, format=None):
serializer = ArticleSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
데코레이터 swagger_auto_schema를 추가하면 http://127.0.0.1:8000/swagger/ 에서 자세한 명세를 볼 수 있다. ('title required' 등..)
Try it out
을 눌러 POST 요청을 할 수 있다.
Postman에서도 같은 POST 요청 결과가 확인된다.
Swagger를 통해서도 편리하게 테스트해볼 수 있다.
frontend와 backend가 나눠져서 테스트를 하다 보면 어디서 에러가 발생했는지 찾는 게 복잡할 때가 많다.
Swagger
나 Postman
을 통해 찾아보면 HTTP status 코드와 함께, {body} 내 key값 오타 등 사소한 에러들을 확인할 수 있다.