Article CRUD
Django에서 만든 Article 모델의 CRUD Operation을 HTML이 아닌 JSON으로 만들어 응답하는 RESTful API 서버로 만들어봐요!
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)
"The serializers in REST framework work very similarly to Django's
Form
andModelForm
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가지 다른 점이 있다.
It will automatically generate a set of fields for you, based on the model.
model에 기반한 필드를 자동으로 생성한다.
It will automatically generate validators for the serializer, such as unique_together validators.
serializer를 위한 기본 validator를 생성한다.
It includes simple default implementations of .create()
and .update()
.
기본적인 .create()
와 .update()
를 포함한다. (지금은 신경쓰지 않아도 되는 부분)
→ ModelSerializer를 통해 QuerySet과 단일 Model Instance를 직렬화해서 JSON으로 응답한다.
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',)
RESTful하게 경로를 설정하자! (참고 : 함수 이름을 길게 작성한 것은 명시성을 위한 것인데, 함축적인 의미를 갖는 짧은 함수 이름보단 길더라도 명시적인 역할이 보이는 함수 이름을 추천)
# ./articles/urls.py
urlpatterns = [
path('', views.article_list_create),
path('<int:article_pk>/', views.article_detail_update_delete),
]
article list 가져오기 → Response 클래스를 활용해 직렬화된 data를 응답한다.
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)
단일 Model Instance 가져오기 ( LIST는 QuerSet 객체를 가져왔음)
# ./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)
요청 데이터를 서버로 받아와서 유저가 요청한대로 처리하기!
응답
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)
데이터 삭제하기!
응답
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)
요청 데이터를 서버로 받아와서 서버를 업데이트하기
일반적으로 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
를 배워볼 예정이다.
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)