아래 사례는 Udemy의 "The complete Guide to Django Restframework and Vue JS" 강의 중 Section3의 : Django REST Framework - Level One의 내용을 요약정리한 것입니다.
앞서 Function-based View로 짠 것과 동일한 역할을 하는 코드를 Class-based View로 짜 봤습니다. ListCreateAPIView는 사실상 함수형 코드와 거의 유사하다. DetailAPIView는 get_object 메소드를 추가하여 사용한다는 점이 큰 차이이다. 클래스형 뷰이기 때문에 함수를 메소드로 지정하여, 재활용할 수 있기 때문이다.
from rest_framework.views import APIView
from rest_framework.generics import get_object_or_404
class ArticleListCreateAPIView(APIView):
def get(self, request):
articles = Article.objects.filter(active=True)
serializer = ArticleSerializer(articles, many=True)
# queryset many=True, Model instance면 없어도 됨.
return Response(serializer.data)
def post(self, request):
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ArticleDetailAPIView(APIView):
def get_object(self, pk):
article = get_object_or_404(Article, pk=pk)
return article
def get(self, request, pk):
article = self.get_object(pk)
serializer = ArticleSerializer(article)
return Response(serializer.data)
def put(self, request, pk):
article = self.get_object(pk)
serializer = ArticleSerializer(article, 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):
article = self.get_object(pk)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
[Debug를 통한 코드 이해]
> /Users/seungholee/udemy_drf/newsapi/news/api/views.py(38)get_object()-><Article: Joh...are publising>
(Pdb) article
<Article: John Titor First articled we are publising>
/Users/seungholee/udemy_drf/newsapi/news/api/views.py(43)get()
(Pdb) self
<news.api.views.ArticleDetailAPIView object at 0x10332c310>
(Pdb) self.get_object(2)
<Article: John Titor How to be CEO it's tough>
REST 프레임워크는 Django View 클래스의 하위 클래스로 APIView 클래스를 제공한다. APIView 클래스는 View 클래스와 아래와 같은 점에서 다른 부분이 있다.
이 외에는 APIView 클래스는 View클래스를 사용하는 것과 동일하다. Incoming request는 .get()이나 .post()와 같은 적절한 핸들러 메서드로 전달된다.
get_object_or_404 함수는 Django Model을 첫번째 인자로 받고, get() 함수에서 전달될 임의의 값을 키워드 인자로 받는다. 만약, 객체가 존재하지 않으면 Http404(page not found)를 띄운다.
article = get_object_or_404(Article, pk=pk)
FBV가 아닌 CBV를 이용해 API views를 작성할 수도 있다. 공통적인 함수를 재사용할 수 있고, 코드를 DRY 정책을 따르도록 하는 강력한 패턴이다.
DRY: Don't Repeat Yourself.
전체적인 모양은 FBV 때와 크게 다르지 않다.
다만 각 메소드명을 HTTP 메소드명과 동일하게 사용하고 있다는 점이 가장 큰 차이점이고,
이전 포스트에서 언급했듯이 FBV에서 사용하던 @api_view
데코레이터 대신에 APIView
클래스를 상속받아 각 용도에 맞는 클래스를 만들었다.
@api_view
데코레이터에 HTTP 메소드를 전달하는 대신 동일한 이름의 메소드를 정의하는 것이다.
FBV 패턴에서는 각 URL마다 호출할 메소드를 직접 명시했다. (views.snippet_list())
CBV 패턴에서는 상속했던 APIView
클래스의 클래스 메소드인 as_view()
를 호출한다.
as_view()
메소드는 해당 클래스의 인스턴스를 생성하고, dispatch()
메소드를 호출한다. 호출된 이 dispatch()
메소드가 요청을 분석해서 어떤 HTTP 메소드 요청인지 얻어낸다. POST
요청이면 앞에서 생성된 인스턴스 안에서 post
라는 이름을 가진 메소드로 요청을 중계한다.
매칭되는 메소드가 정의되지 않은 경우, HTTPResponseNotAllowed
예외를 발생시킨다.