DRF 03 CRUD 적용

Seungju Hwang·2020년 12월 15일
0

django

목록 보기
7/11
post-thumbnail

Intro

Article CRUD
Django에서 만든 Article 모델의 CRUD Operation을 HTML이 아닌 JSON으로 만들어 응답하는 RESTful API 서버로 만들어봐요!


🔵 Postman 설치 ⭐

A powerful GUI platform to make your API development faster & easier, from building API requests through testing, documentation and sharing.

→ Postman은 개발한 API를 테스트하고, 테스트 결과를 공유하여 API 개발의 생산성을 높여주는 플랫폼

collection을 활용해서 서버마다 확인해야할 api를 저장할 수 있다! ( 저장 : ctrl+s / 실행 : ctrl+enter)


🔵 ModelSerializer 란?

"The serializers in REST framework work very similarly to Django's Form and ModelForm classes."

→ Django의 form class와 ModelForm과 매우 유사하다.

# DRF의 serializers.py

from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
  
    class Meta:
        model = Article
        fields = ('id', 'title',)
# Django의 forms.py

from django import forms
from .models import Article, Comment

class ArticleForm(forms.ModelForm):
    
    class Meta:
        model = Article
        fields = ('title', 'content',)

ModelSerializer는 Serializer와 거의 대부분 비슷하게 동작하지만, 3가지 다른 점이 있다.

  1. It will automatically generate a set of fields for you, based on the model.

    model에 기반한 필드를 자동으로 생성한다.

  2. It will automatically generate validators for the serializer, such as unique_together validators.

    serializer를 위한 기본 validator를 생성한다.

  3. It includes simple default implementations of .create() and .update().

    기본적인 .create().update() 를 포함한다. (지금은 신경쓰지 않아도 되는 부분)

→ ModelSerializer를 통해 QuerySet과 단일 Model Instance를 직렬화해서 JSON으로 응답한다.


🔵 CRUD 적용

Serializer 정의

  • many=True : 댓글 데이터는 쿼리셋으로 들어오기 때문에 다음과 같은 인자 필수!
  • read_only=True : ArticleListSerializer를 활용하여 article를 create할 때, request.data에서 받아오지 않는 데이터 필드의 경우는, 읽기전용으로 정의를 내려줘야한다.
# ./articles/serializers.py
from rest_framework import serializers
from .models import Article,Comment

class ArticleListSerializer(serializers.ModelSerializer):
    '''
    시리얼라이저를 사용하는 이유 2가지
    1. 데이터베이스에서 가져온 쿼리셋을 JSON으로 바꿔서 응답해준다!
    2. 요청으로 받아온 JSON 형태의 데이터를 반대로 파이썬 객체로 만들어줌!
    '''
    comment_set = CommentSerializer(many=True, read_only=True)
    comment_count = serializers.IntegerField(source='comment_set.count',read_only=True)
    class Meta:
        model = Article
        fields = ('id','title','content','created_at','updated_at','comment_set','comment_count',)

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ('id','title','content','created_at','updated_at',)

URL 경로 설정

RESTful하게 경로를 설정하자! (참고 : 함수 이름을 길게 작성한 것은 명시성을 위한 것인데, 함축적인 의미를 갖는 짧은 함수 이름보단 길더라도 명시적인 역할이 보이는 함수 이름을 추천)

# ./articles/urls.py

urlpatterns = [
    path('', views.article_list_create),
    path('<int:article_pk>/', views.article_detail_update_delete),
]

GET(LIST)

article list 가져오기 → Response 클래스를 활용해 직렬화된 data를 응답한다.

  1. views

Django와 다르게 HTTP Method를 처리하기 위한 @api_view 데코레이터를 추가하지 않으면 에러가 발생한다.

# ./articles/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view

from .models import Article
from .serializers import ArticleListSerializer

@api_view(['GET'])
def article_list_create(request):
    '''
    GET /api/v1/articles
    '''
    # 만약 method =='GET' 
    if request.method =='GET':
        # 1. 디비에 있는 모든 게시글을 가져온다.
				# 2. 전송 가능한 형태(JSON)으로 바꿔준다.
				# 3. 마지막으로 Response 함수를 이용하여 반환
        articles = Article.objects.all()
        serializer = ArticleListSerializer(articles,many=True) # 보내는 데이터가 여러개일 경우
        
				return Response(data=serializer.data)
  1. output

GET(DETAIL)

단일 Model Instance 가져오기 ( LIST는 QuerSet 객체를 가져왔음)

  1. views
# ./articles/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view

from django.shortcuts import render,get_object_or_404
from .models import Article
from .serializers import ArticleSerializer

  
@api_view(['GET'])
def article_detail_update_delete(request,article_pk):
    article = get_object_or_404(Article,pk=article_pk)
		'''
    GET /api/v1/articles/{article_pk}
    '''
    if request.method=='GET':
        serializer = ArticleSerializer(article) #JSON으로 만들기
        return Response(serializer.data)
  1. 결과

POST(CREATE)

요청 데이터를 서버로 받아와서 유저가 요청한대로 처리하기!

  1. view
  • 응답

    Django: request.GET, request.POST과 같은 형태로 HTML 넘긴 데이터를 서버로 받아와 데이터를 처리했다.

    DRF: 요청 데이터를 request.data를 통해 가져올 수 있다.

  • 응답메시지 : 200 status 이 기본이지만, .DRF 공식문서를 통해서 커스텀 가능!

  • 유효성 검사 : raise_exception=True 를 통해 validation을 통과하지 못하는 상황에 대한 예외처리가 가능하며, 어떤 필드가 통과하지 못했는 지 알려준다.

  • 같은 URI를 사용하지만 http method가 달라서 하는 기능이 다르다는 거!!

# ./articles/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view

from .models import Article
from .serializers import ArticleListSerializer

@api_view(['GET','POST'])
def article_list_create(request):
    '''
    GET /api/v1/articles
		POST /api/v1/articles
    '''
    # 만약 method =='GET' 
    if request.method =='GET':
        articles = Article.objects.all()
        serializer = ArticleListSerializer(articles,many=True)
				return Response(data=serializer.data)

		if request.method =='POST':
        # JSON을 python 데이터타입으로 변환
        serializer = ArticleListSerializer(data=request.data)
        # 유효성 검사
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(data=serializer.data,status=status.HTTP_201_CREATED)
  1. 결과

DELETE(DELETE)

데이터 삭제하기!

  1. view
  • 응답

    DELETE의 경우 서버에서 리소스를 삭제했기 때문에 응답으로 줄 것이 없다. (그러나 아래 코드는 삭제된 article의 pk를 알려주는 것으로 만들었다)

    204 No content status 코드를 활용하면 적절. + 이후에는 같은 요청에 대해 404 응답 코드 반환!

# ./articles/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view

from django.shortcuts import render,get_object_or_404
from .models import Article
from .serializers import ArticleSerializer

  
@api_view(['GET','DELETE'])
def article_detail_update_delete(request,article_pk):
    article = get_object_or_404(Article,pk=article_pk)
		'''
    GET /api/v1/articles/{article_pk}
		DELETE /api/v1/articles/{article_pk}
    '''
    if request.method=='GET':
        serializer = ArticleSerializer(article) #JSON으로 만들기
        return Response(serializer.data)
		
		elif request.method=='DELETE':
				article.delete()
				data={
            'article':article_pk
        }
				return Response(data,status=status.HTTP_204_NO_CONTENT)
  1. output

PUT(UPDATE) ⭐

요청 데이터를 서버로 받아와서 서버를 업데이트하기

일반적으로 PUT은 PATCH와 구분해서 사용하기 때문에 HTTP status code 코드도 구분해서 응답한다.

PUT : 자원 전부 교체

PATCH: 자원 일부 교체

→ patch 영어 뜻은 덧덴 천조각, 좁은 지면 등이 있다. 그리고 게임 패치한다 라는 건 게임의 일부분을 업데이트한다는 말이기도 하다. 따라서 PATCH 란 일부분을 바꿔주는 부분이다!!

중요한 차이

# GET /api/v1/articles/1
{ 
	"title" : "테스트",
	"content" : "테스트데이터입니다" 
}

#PUT /api/v1/articles/1
{
	"title" : "수정!",
}

# result GET /api/v1/articles/1
{
	"title" : "수정!",
	"content" : null
}

→ PUT이용할 때, 모든 필드에 데이터를 넣지 않으면 NULL로 필드가 채워진다..

#PATCH /api/v1/articles/1
{
	"title" : "수정!",
}

# GET /api/v1/articles/1
{
	"title" : "수정!",
	"content" : "테스트데이터입니다" 
}

→ PATCH는 필드 값 유지된다!

하지만, 대부분의 서버에선 PATCH를 지원하지 않는다! 따라서 본문에선 PUT 를 배워볼 예정이다.

  1. view
  • 업데이트를 할 땐, instance 키워드가 필요하다.
# ./articles/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view

from django.shortcuts import render,get_object_or_404
from .models import Article
from .serializers import ArticleSerializer

  
@api_view(['GET','DELETE','PUT'])
def article_detail_update_delete(request,article_pk):
    article = get_object_or_404(Article,pk=article_pk)
		'''
    GET /api/v1/articles/{article_pk}
		DELETE /api/v1/articles/{article_pk}
		PUT /api/v1/articles/{article_pk}
    '''
    if request.method=='GET':
        serializer = ArticleSerializer(article) #JSON으로 만들기
        return Response(serializer.data)
		
		elif request.method=='DELETE':
				article.delete()
				data={
            'article':article_pk
        }
				return Response(data,status=status.HTTP_204_NO_CONTENT)
		
		elif request.method == 'PUT':
        serializer = ArticleSerializer(instance=article, data=request.data)
        if serializer.is_valid():
            serializer.save()
        return Response(serializer.data)
  1. output
profile
기록하는 습관은 쉽게 무너지지 않아요.

0개의 댓글