[DRF] 간단한 책 정보 검색 API 만들기

mia·2024년 8월 5일
post-thumbnail

모델 ➡️ 시리얼라이저 ➡️ 뷰 ➡️ URL 순서로 생성해보자

모델


실제 교보문고 사이트를 기반으로 모델을 생성해보자

  • 필요한 필드 :

    • 책 ID
    • 책 제목
    • 저자
    • 출판사
    • 카테고리
    • 페이지 수
    • 가격
    • 출판일
    • 도서 설명
  • models.IntegerField(primary_key=True)

    • 모델에서 Django는 자동으로 id값을 pk로 생성한다
    • (primary_key=True)를 명시해주면 다른 값을 사용자 정의 pk로 사용할 수 있다
class Book(models.Model):
    bid = models.IntegerField(primary_key=True)
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)
    publisher = models.CharField(max_length=50)
    category = models.CharField(max_length=50)
    pages = models.IntegerField()
    price = models.IntegerField()
    published_date = models.DateField()
    description = models.TextField()
  • 모델을 작성했으므로 마이그레이션한다
$ py manage.py makemigrations
$ py manage.py migrate



시리얼라이저

  • 모델을 만들고 뷰를 작성하기 전 단계에서 만들어준다
  • example/serializers.py 파일을 생성한다.
    시리얼라이저 만드는 방법은 2개!
  1. serializers.Serializer를 사용한다
  • 모델의 필드 내용을 그대로 작성
  • create, update 함수를 직접 정의해 POST 요청으로 들어온 데이터를 파이썬 모델 형태로 Deserialize하여 데이터베이스에 집어넣을 때 사용
  • 같은 내용이 반복되고 코드가 길어 비효율적
  • 코드는 생략
  1. serializers.ModelSerializer를 사용한다
  • ModelSerializer : 모델의 내용을 기반으로 동작하는 시리얼라이저
  • 코드의 중복을 줄일 수 있고 훨씬 간편하다
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['bid', 'title', 'author', 'publisher', 'category', 'pages', 'price', 'published_date', 'description']



  • 책 정보 검색 API
    • GET /books/ : 전체 책 정보를 가져오는 API
    • GET /book/1 : bid에 해당하는 책 1권의 정보를 가져오는 API
    • POST /books/ : 책 정보를 등록하는 API
  • 전체 책 정보를 조회하는 API와 책 정보를 등록하는 API의 주소가 같다는 점에 유의한다

함수형 뷰로 작성한 코드

from rest_framework import viewsets, permissions, generics, status
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
from .models import Book
from .serializers import BookSerializer

@api_view(['GET'])
def HelloAPI(request):
    return Response("hello world!")

@api_view(['GET', 'POST'])      # GET/POST 요청을 처리해주는 데코레이터
def booksAPI(request):      # /books/
    if request.method == 'GET':
        books = Book.objects.all()      # Book 모델로부터 전체 데이터 가져오기
        serializer = BookSerializer(books, many=True)
        # 시리얼라이저에 전체 데이터를 한번에 집어넣기(직렬화, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
    elif request.method == 'POST':
        serializer = BookSerializer(data=request.data)
        # POST 요청으로 들어온 데이터를 시리얼라이저에 집어넣기
        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):
    book = get_object_or_404(Book, bid=bid)
    serializer = BookSerializer(book)       # 시리얼라이저에 데이터 집어넣기(직렬화)
    return Response(serializer.data, status=status.HTTP_200_OK)
  • booksAPI() 함수 : /books/ 주소를 사용할 두 API를 처리하는 함수
    • 조건문을 통해 요청이 GET인지 POST인지에 따라 다르게 처리
  • 책 전체 정보를 가져오는 GET 요청
    • Book.objects.all()을 통해 모델로부터 전체 데이터를 가져온다
    • many=True 옵션으로 여러 데이터를 시리얼라이저에 집어넣어 직렬화한다
    • 데이터를 잘 가져왔으면 200 메시지를 보낸다
  • 책 정보를 등록하는 POST 요청
    • 요청으로 들어온 데이터를 역직렬화하여 모델에 집어넣어야 하므로, request.data를 시리얼라이저에 넣는다
    • 시리얼라이저의 is_valid() 검사로 유효한 데이터인 경우 저장한다
    • serialize.save()create() 함수를 실행시키는 모델시리얼라이저의 기본 기능
    • 잘 저장된 경우 201 메시지, 아닌 경우 400 메시지를 보낸다
  • bookAPI() 함수 : 특정 책 데이터를 조회하는 함수
    • 함수의 인자로 id를 넘겨받아 이를 Book 모델에서 찾는다
    • 찾은 데이터를 시리얼라이저에 넣은 뒤 반환한다

클래스형 뷰로 작성한 코드

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.errors, 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)
  • 클래스 내에 GET과 POST를 따로 정의해 주므로 데코레이터나 조건문 사용 X



URL

함수형 뷰 연결

from django.urls import path, include
from .views import HelloAPI, booksAPI, bookAPI, BooksAPI, BookAPI

urlpatterns = [
    path("hello/", HelloAPI),
    path("fbv/books/", booksAPI),
    path("fbv/book/<int:bid>/", bookAPI),

http://127.0.0.1:8000/example/fbv/books/
위 주소로 들어가보면 요런 화면이 뜬다

Content란에 데이터를 입력해보자

{
"bid": 1,
"title": "고양이 마음 사전",
"author": "나응식",
"publisher": "주니어김영사",
"category": "동물/곤충/공룡",
"pages": 160,
"price": 12800,
"published_date": "2020-05-07",
"description": "고양이가 일상생활에서 표현하는 60여 개의 마음을 담다"
}

POST 버튼을 누른 뒤 화면
이제 http://127.0.0.1:8000/example/fbv/book/1 주소로 들어가보면

bid 값이 1인 책의 정보가 뜬다


클래스형 뷰 연결

  • 클래스형 뷰는 함수형 뷰와 달리 path에 등록할 때 .as_view()를 사용
from django.urls import path, include
from .views import HelloAPI, booksAPI, bookAPI, BooksAPI, BookAPI

urlpatterns = [
    path("hello/", HelloAPI),
    path("fbv/books/", booksAPI),
    path("fbv/book/<int:bid>/", bookAPI),
    path("cbv/books/", BooksAPI.as_view()),
    path("cbv/book/<int:bid>", BookAPI.as_view()),
]

http://127.0.0.1:8000/example/cbv/books/ 에 접속해보면

함수형 뷰의 /books/ 페이지와 동일한 화면이 뜬다
Content란에 두 번째 책 정보를 기입해보자

{
"bid": 2,
"title": "당신이 누군가를 죽였다",
"author": "히가시노 게이고",
"publisher": "북다",
"category": "미스터리/스릴러소설",
"pages": 432,
"price": 19800,
"published_date": "2024-07-23",
"description": "고한여름 호화 별장지에서 일어난 연속 살인사건"
}


잘 추가됐다❗
/cbv/book/1 or /cbv/book/2 상세 페이지에 들어가도 책 정보를 볼 수 있다

함수형 뷰와 클래스형 뷰의 모든 기능이 동일하게 잘 작동한다
성공!

profile
바보

0개의 댓글