본문 바로가기
Python/Django Ⅱ

DRF 예제2 : 데코레이터, reponse 상태코드, FBV/CBV, mixins/generic 클래스

by Mr.DonyStark 2024. 5. 18.

□ 이전 글에서는 DRF(Django Rest Framework) 구현 중 json형태의 데이터 변환을 위한 시리얼라이즈와 디시리얼라이즈 구현을 하였음.

https://dandora-90.tistory.com/350

 

DRF 예제1 : Django REST Framework

□ Django 와 DRF 차이점특징Pure DjangoDjango Rest Framework개발 목적웹 풀스택 개발백앤드 API 서버 개발개발 결과웹 페이지를 포함한 웹 서비스여러 클라이언트에서 사용할 수 있는 API 서버응답 형태HTML

dandora-90.tistory.com

 

□ models.py와 Serializers.py 구현을 했다면 이제는 views.py를 구현할 차례임.

구현하기에 앞서 데코레이터, reponse의 상태코드, FBV/CBV, mixins 클래스, generic 클래스를 파악해보자

  ○ 데코레이터 : 말 그대로 함수를 꾸미는 역할 즉, 우리가 작성한 함수의 앞뒤에 무언가 기능을 붙여 함수를 포함하는 함수 형태로 만드는 것임. 함수를 인자로 받는 하나의 함수라고 생각하면되겠음. API로 동작하기 위해 앞뒤로 전처리, 후처리 코드를 덧붙여 실제 API로 동작, 활용할 수 있도록함

ex) @api_view(["GET"]), @api_view(["POST"]) , @api_view(["GET" , "POST"])  

 

  ○ Rsoponse

    - request객체는 요청을 효과적으로 처리해주고 인증기능을 구현할 때 편리함을 제공해주며 DRF API 서버로 요청을 보낼때 해당 요청에 대한 정보를 담고 있음. 즉, 사용자가 보낸 요청이 무슨 데이터를 함깨 보냈는지 request.data, 어떤 타입을 요청했는지 request.method로 파악할 수 있음.

    - 반면 결과를 반환할 때는 Response라는 클래스를 사용하며 이는 응답에 대한 정보를 담고있는데, response.data에는 응답에 포함되는 데이터, response.status에는 응답에 대한 상태정보가 있음.

    - response.status : request에 대한 응답이 어떤 상태인지 알려주는 규격화되는 코드값

HTTP_200_OK Get 요청이 정상적으로 이뤄졌을 때 응답에 나타나는 상태값
HTTP_201_CREATED 데이터 생성관련 POST요청이 정상적을 이뤄졌을때 응답에 나타나는 상태값
HTTP_206_PARTIAL_CONTENT 데이터를 일부 수정하는 PATCH요청이 정상적으로 이뤄졌을때 응답에 나타나는 상태값
HTTP_400_BAD_REQUEST 잘못된 요청을 보냈을 떄(클라이언트가) 응답에 나타나는 상태값임
HTTP_401_UNAUTHORIZED 인증이 필요한데 인증관련 내용이 요청에 없을때 응답에 나타나는 상태값임
HTTP_403_FORBIDDEN 클라이언트가 접근하지 못하도록 막아놓은 곳에 요청이 왔을때 응답에 나타나는 상태값
HTTP_404_NOT_FOUND 클라이언트가 요청을 보낸 곳이 잘못된 URL일 때(리소스가 없을때)응답에 나타나는 상태값
HTTP_500_INTERNAL_SERVER_ERROR 서버 쪽에서 코드가 잘못되었을 때 응답에 나타나는 상태값

 

  ○ FBV/CBV

    - FBV(Function Based View) : 함수 기반 뷰

    - CBV(Class Based View) : 클래스 기반 뷰

#함수기반 뷰 FBV : Function Based View
@api_view(["GET"])
def HelloAPI(request):
    return Response("hello world!")
#클래스기반 뷰 CBV : Class Based View, CBV
class HelloAPI(APIView):
    def get(self,request):
        return Response("hello world!")

 

  ○ mixins 클래스

     ● mixins.ListModelMixin
       - Queryset을 리스팅하는 믹스인
       - .list(request, *args, **kwargs) 메소드로 호출하여 사용
       - enericAPIView의 self.filter_queryset, self.get_queryset, self.get_serializer 등의 메소드를 활용해 데이터베이스에 저장되어 있는 데이터들을 목록 형태로 response body로 리턴
       - 성공 시, 200 OK response 리턴
    ● mixins.CreateModelMixin
       - 모델 인스턴스를 생성하고 저장하는 역할을 하는 믹스인
       - .create(request, *args, **kwargs) 메소드로 호출하여 사용
       - 성공 시, 201 Created 리턴
       - 실패 시, 400 Bad Request 리턴
    ● mixins.RetrieveModelMixin
       - 존재하는 모델 인스턴스를 리턴해 주는 믹스인
       - .retrieve(request, *args, **kwargs) 메소드로 호출하여 사용
       - 성공 시, 200 OK response 리턴
       - 실패 시, 404 Not Found 리턴
    ● mixins.UpdateModelMixin
       - 모델 인스턴스를 수정하여 저장해 주는 믹스인
       - .update(request, *args, **kwargs) 메소드로 호출하여 사용
       - 부분만 변경하고자 할 경우, .partial_update(request, *args, **kwargs)메소드를 호출하여야 하며, 이 때 요청은 HTTP PATCH requests여야 함
       - 성공 시, 200 OK response 리턴
       - 실패 시, 404 Not Found 리턴
   ● mixins.DestoryModelMixin
        - 모델 인스턴스를 삭제하는 믹스인
       - .destroy(request, *args, **kwargs) 메소드로 호출하여 사용
       - 성공 시, 204 No Content 리턴
       - 실패 시, 404 Not Found 리턴

# from django.shortcuts import render DRF 예제를 위해 주석처리
from rest_framework import viewsets, permissions, generics, status
from rest_framework import mixins
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.decorators import api_view
from rest_framework.generics import get_object_or_404 #get_object_or_404 호출
from .models import Book #example app의 model 호출
from .serializers import BookSerializer  #example app의 serializer 호출
   
class BooksAPIMixminx(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
    queryset=Book.objects.all() #model로 부터 받은 모든 데이터
    serializer_class = BookSerializer #API에서 사용할 시리얼라이저
    #Get 메서드 : mixins.ListModelMixin 
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    #Post 메서드 : mixins.CreateModelMixin 1권등록
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
    
class BookAPIMixins(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    #DJango 기본모델의 pk 가 아닌 bid를 pk로 사용하고 있기에 look_upfield로 설정
    lookup_field = "bid"
    #Get메서드 : mixins.RetrieveModelMixin 1권 조회
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    #put 메서드 : mixins.UpdateModelMixin 1권 수정
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    #delete 메서드 : mixins.DestroyModelMixin 1권 삭제
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

 

  ○ genrics 클래스 : mixins를 상속받는데 한번에 2~3개씩 상속을 받아야하는데, 이러한 번거로움을 해결하기 위해 사용

    ● generics.ListAPIView : 전체목록

    ● generics.CreateAPIView : 생성

    ● generics.RetreieveAPIView : 1개

    ● generics.UpdateAPIView : 1개 수정

    ● generics.DestroyAPIView : 1개 삭제

    ● generics.ListCreateAPIView : 전체목록 + 생성

    ● generics.RereieveUpdateAPIView : 1개 + 1개 수정

    ● generics.RereieveDestroyAPIView : 1개 + 1개 삭제

    ● generics.RereieveUpdateDestroyAPIView  : 1개 + 1개 수정 + 1개 삭제

# from django.shortcuts import render DRF 예제를 위해 주석처리
from rest_framework import viewsets, permissions, generics, status
from rest_framework import mixins
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.decorators import api_view
from rest_framework.generics import get_object_or_404 #get_object_or_404 호출
from .models import Book #example app의 model 호출
from .serializers import BookSerializer  #example app의 serializer 호출
   
class BooksAPIGenerics(generics.ListCreateAPIView):
    queryset=Book.objects.all()
    serializer_class=BookSerializer

class BookAPIGenerics(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    lookup_field = "bid"

 

□ 전체코드

  ○ Models.py

from django.db import models

#example app에 대한 모델 Book 클래스 생성
class Book(models.Model):
    bid = models.AutoField(primary_key=True) #book id
    title = models.CharField(max_length=50) #book 제목
    author = models.CharField(max_length=50) #book 작가
    category = models.CharField(max_length=50) #book 분류
    pages = models.IntegerField() #book 페이지수
    price = models.IntegerField() #book 가격
    published_date = models.DateField() #book 출판일
    description = models.TextField() #book 요약

 

  ○ Views.py

# from django.shortcuts import render DRF 예제를 위해 주석처리
from rest_framework import viewsets, permissions, generics, status
from rest_framework import mixins
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.decorators import api_view
from rest_framework.generics import get_object_or_404 #get_object_or_404 호출
from .models import Book #example app의 model 호출
from .serializers import BookSerializer  #example app의 serializer 호출


#함수기반 뷰 FBV : Function Based View
@api_view(["GET"])
def HelloAPI(request):
    return Response("hello world!")
#클래스기반 뷰 CBV : Class Based View, CBV
class HelloAPI(APIView):
    def get(self,request):
        return Response("hello world!")

#함수기반 뷰 FBV : Function Based View
@api_view(["GET","POST"]) #GET, POST 요청처리를 해줄 데코레이터
def booksAPI(request): #example/book
    if request.method == "GET":  #GET요청 : 도서정보조회
        books = Book.objects.all() #모든 데이터를 가져와 books에 저장
        #시리얼라이저 전체 데이터를 한번에 넣기(질렬화, many=True)
        serializer = BookSerializer(books, many=True) #books에 들어온 데이터는 1개 이상으로 many=True 지정
        return Response(serializer.data, status=status.HTTP_200_OK) #return response

        #post 요청으로 들어온 데이터 시리얼라이저에 집어넣기
    elif request.method == "POST": #POST요청 : 도서정보등록
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid(): 
            serializer.save()#시러얼라이저의 역직렬화로 save()
            #모델시리얼라이저의 create함수 실행
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
@api_view(["GET"])
def bookAPI(request,bid):
    #bid =id인 데이터를 Book에서 가져오고 없으면 404dpfj
    book = get_object_or_404(Book, bid=bid)
    serializer = BookSerializer(book) #시러얼라이저에 데이터 넣기
    return Response(serializer.data, status=status.HTTP_200_OK)


#클래스기반 뷰 CBV : Class Based View, CBV
class BooksAPI(APIView):
    def get(self,request):
        books = Book.objects.all()
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
    def post(self, request):
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)
    
class BookAPI(APIView):
    def get(self, request, bid):
        book = get_object_or_404(Book, bid=bid)
        serializer = BookSerializer(book)
        return Response(serializer.data, status=status.HTTP_200_OK)
    
class BooksAPIMixminx(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
    queryset=Book.objects.all() #model로 부터 받은 모든 데이터
    serializer_class = BookSerializer #API에서 사용할 시리얼라이저
    #Get 메서드 : mixins.ListModelMixin 
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    #Post 메서드 : mixins.CreateModelMixin 1권등록
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
    
class BookAPIMixins(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    #DJango 기본모델의 pk 가 아닌 bid를 pk로 사용하고 있기에 look_upfield로 설정
    lookup_field = "bid"
    #Get메서드 : mixins.RetrieveModelMixin 1권 조회
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    #put 메서드 : mixins.UpdateModelMixin 1권 수정
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    #delete 메서드 : mixins.DestroyModelMixin 1권 삭제
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
    
class BooksAPIGenerics(generics.ListCreateAPIView):
    queryset=Book.objects.all()
    serializer_class=BookSerializer

class BookAPIGenerics(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    lookup_field = "bid"

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

 

  ○ app > Urls.py

from django.urls import path, include
from .views import HelloAPI, booksAPI, bookAPI, BooksAPI, BookAPI, BooksAPIMixminx, BookAPIMixins, BooksAPIGenerics, BookAPIGenerics

urlpatterns = [
    path("hello/", HelloAPI), #app명/hello/ 의미 : example/hello/
    path("fbv/books/", booksAPI), #함수형 view > booksAPI 연결 : Function Based View
    path("fbv/book/<int:bid>/", bookAPI),  #함수형 view > bookAPI 연결 : Function Based View
    path("cbv/books/", BooksAPI.as_view()),
    path("cbv/book/<int:bid>/", BookAPI.as_view()),
    path("mixin/books/", BooksAPIMixminx.as_view()),
    path("mixin/book/<int:bid>/", BookAPIMixins.as_view()),
    path("otherset/books/",BooksAPIGenerics.as_view()),
    path("otherset/book/<int:bid>/",BookAPIGenerics.as_view())
]

 

  ○ pjt > Urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path("example/", include("example.urls")) #example app url을 include 함수를 써서 추가
]

 

generics.ListCreateAPIView(전체목록 + 생성) 을 클래스 사용과 JSON 타입으로 데이터를 POST/GET방식으로 전달

 

generics. RereieveUpdateDestroyAPIView(1개 + 1개 수정 + 1개 삭제) 클래스 사용과 JSON 타입으로 데이터를 POST/GET방식으로 전달. 수정과 삭제가 가능하며 등록된 것을 1개 조회 가능.

 

'Python > Django Ⅱ' 카테고리의 다른 글

DRF 예제1 : Django REST Framework  (0) 2024.05.18
Todo : Update  (0) 2024.05.15
Todo : Create, Read  (0) 2024.05.15
Django 게시물 수정하기  (0) 2024.05.14
Django Form 기능 / 게시물 등록하기  (0) 2024.05.14