앞으로 모든 데이터를 json이라는 형식으로 주고받을 것이다.
json은 딕셔너리 형태와 비슷하게 생겼다!!
from rest_framework.response import Response
from rest_framework.decorators import api_view
@api_view(['GET'])
def index(request):
return Response("확인")
이전에는 template을 생성하고 render를 이용하여 화면을 띄웠지만 django rest framework에서는 Response를 이용해 화면에 띄운다.
위의 코드에서 POST를 추가하면
from rest_framework.response import Response
from rest_framework.decorators import api_view
# Create your views here.
@api_view(['GET', 'POST'])
def index(request):
return Response("확인")
이렇게 화면에 뜨게 된다!!!
api_view는 restframework에서 api들을 간단하게 사용할 수 있게 하는 기능을 한다.
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
# Create your views here.
@api_view(['GET'])
def index(request):
articles = Article.objects.all()
return Response(articles)
이 방법으로 하면 오류가 난다.
왜?? 데이터를 넘겨주는 형식이 json형태가 아니기 때문에!!
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
# Create your views here.
@api_view(['GET'])
def index(request):
articles = Article.objects.all()
article = articles[0]
article_data ={
'title':article.title,
'content':article.content,
'created_at':article.created_at,
'updated_at':article.updated_at,
}
return Response(article_data)
json 형태로 데이터를 넘겨주려면 위의 코드처럼 작성해야 하는데 이렇게 하면 코드가 너무 길어지게 된다.
때문에 이 문제를 해결하기 위해 사용하는 것이 바로 serializer이다!!
데이터를 json형태로 바꿔주는 기능을 한다!!!
데코레이터란 쉽게 말하면 함수를 꾸며주는 함수이다!
인자를 함수로 받고 받은 함수값의 위 아래 부분에 새롭게 실행하는 값(코드)을 추가해서 꾸며진 함수를 리턴시켜준다!
def wrapper_function(func):
def decorated_function():
print("함수 이전에 실행")
func()
print("함수 이후에 실행")
return decorated_function
def basic_function():
print("실행하고자 하는 함수")
new_function = wrapper_function(basic_function)
new_function()
def wrapper_function(func):
def decorated_function():
print("함수 이전에 실행")
func()
print("함수 이후에 실행")
return decorated_function
@wrapper_function
def basic_function():
print("실행하고자 하는 함수")
basic_function()
# new_function = wrapper_function(basic_function)
# new_function()
데코레이터 함수를 실행하면 basic_function만 두어도 @wrapper_function 때문에 예시 1과 동일한 결과가 나온다.
위처럼 @를 사용하여 코드를 축약시킬 수 있다!!
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
from articles.serializers import ArticleSerializer
# Create your views here.
@api_view(['GET'])
def articleAPI(request):
articles = Article.objects.all()
article = articles[0]
serializer = ArticleSerializer(article) # ArticleSerializer이 article을 json형태로 바꿔준다.
return Response(serializer.data) # sertializer만 적으면 오류가 나고(데이터값이 없어서) .data를 붙여줘야된다. data에 결과값이 저장된다.
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
from articles.serializers import ArticleSerializer
# Create your views here.
@api_view(['GET'])
def articleAPI(request):
articles = Article.objects.all()
serializer = ArticleSerializer(articles) # ArticleSerializer이 article을 json형태로 바꿔준다.
return Response(serializer.data) # sertializer만 적으면 오류가 나고(데이터값이 없어서) .data를 붙여줘야된다. data에 결과값이 저장된다.
여러개의 데이터를 보낼 때 위와같은 방식으로 데이터를 전송하면 오류가 난다.
왜?? 데이터가 쿼리셋 형태이기 때문에!!
이럴 때는 serializer에 many=True라는 값을 넣어주면 된다!
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
from articles.serializers import ArticleSerializer
# Create your views here.
@api_view(['GET'])
def articleAPI(request):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data) # sertializer만 적으면 오류가 나고(데이터값이 없어서) .data를 붙여줘야된다. data에 결과값이 저장된다.
이렇게 작성하면 serializer가 article이 여러개가 온다고 인식하고 list형태로 데이터를 바꿔준다.
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
from articles.serializers import ArticleSerializer
# Create your views here.
@api_view(['GET', 'POST'])
def articleAPI(request):
if request.method == 'GET':
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data) # sertializer만 적으면 오류가 나고(데이터값이 없어서) .data를 붙여줘야된다. data에 결과값이 저장된다.
elif request.method == 'POST':
serializer = ArticleSerializer(data = request.data)
if serializer.is_valid(): # 데이터가 유효한지 검사해야함(필수)
serializer.save() # 저장 필수
return Response(serializer.data) # 완성된 데이터를 화면으로 돌려보내준다.
else:
print(serializer.errors)
return Response(serializer.errors) # 에러값을 화면으로 돌려보내준다.(개발중에는 괜찮지만 보안상에는 좋지 않다.)
post 보낼때는 in_valid로 데이터가 유효한지 검사한 후 전송할 수 있다.
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
from articles.serializers import ArticleSerializer
# Create your views here.
@api_view(['GET', 'POST'])
def articleAPI(request):
if request.method == 'GET':
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data) # sertializer만 적으면 오류가 나고(데이터값이 없어서) .data를 붙여줘야된다. data에 결과값이 저장된다.
elif request.method == 'POST':
serializer = ArticleSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.generics import get_object_or_404
from articles.models import Article
from articles.serializers import ArticleSerializer
# Create your views here.
@api_view(['GET', 'POST'])
def articleAPI(request):
if request.method == 'GET':
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data) # sertializer만 적으면 오류가 나고(데이터값이 없어서) .data를 붙여줘야된다. data에 결과값이 저장된다.
elif request.method == 'POST':
serializer = ArticleSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'PUT', 'DELETE'])
def articleDetailAPI(request, article_id):
if request.method == 'GET':
article = get_object_or_404(Article, id=article_id) # 이상한 id로 검색했을 때 404페이지가 뜨도록!
serializers = ArticleSerializer(article)
return Response(serializers.data)
elif request.method == 'PUT':
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article, data = request.data) # article이 기존 데이터 data = request.data가 나중에 들어온 데이터
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
elif request.method == 'DELETE':
article = get_object_or_404(Article, id=article_id)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
포스트맨으로 게시글 확인, 작성, 수정, 삭제 모두 가능하다!
서버와 서버 혹은 클라이언트와 서버 사이에 데이터를 주고받을 때 사용하는 데이터 형식
많은 언어들이 키벨류 형식으로 되어있는데 통신을 위해 이것들을 json으로 바꾸는 것을 시리얼라이제이션이라고 한다.
반대로 json을 각 언어의 자료구조로 만드는 것을 디시리얼라이제이션이라고 한다.
파싱은 디시리얼라이제이션을 포함하는 더 넓은 의미로 데이터를 보고 의미를 해석하는 과정이다.
parse는 데이터의 의미 해석을 뜻한다.
swagger란 프로젝트 분석을 해서 알아서 자동으로 api를 만들어주는 툴
swagger 관련 자료 : https://drf-yasg.readthedocs.io/en/stable/readme.html
pip install drf-yasg
INSTALLED_APPS = [
...
'django.contrib.staticfiles', # required for serving swagger ui's css/js files
'drf_yasg',
...
]
...
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
...
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact@snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
...
]
해당 내용들을 추가하고 http://127.0.0.1:8000/swagger/ 로 들어가면 각 api들이 나오는 창이 뜬다!!
클래스형 view 예시 자료 : https://www.django-rest-framework.org/tutorial/3-class-based-views/
클래스형으로 view를 바꾸면 더 강력한 기능들이 추가된다.
=> 형태가 클래스여서 이것저것들을 상속받을 수 있다.
class ArticleList(APIView):
def get(self, request, format=None):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = ArticleSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ArticleDetail(APIView):
def get(self, request, article_id, format=None):
article = get_object_or_404(Article, id=article_id) # 이상한 id로 검색했을 때 404페이지가 뜨도록!
serializers = ArticleSerializer(article)
return Response(serializers.data)
def put(self, request, article_id, format=None):
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article, data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, article_id, format=None):
article = get_object_or_404(Article, id=article_id)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
from django.urls import path
from articles import views
urlpatterns = [
path('', views.ArticleList.as_view(), name='index'), # 클래스형 view를 가져올 때는 views.클래스형 이름.as_view로 작성해야 함.
path('<int:article_id>/', views.ArticleDetail.as_view(), name='article_view'),
]
클래스형 view를 가져올 때는 views.클래스형 이름.as_view로 작성해야 한다!!
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from rest_framework.generics import get_object_or_404
from articles.models import Article
from articles.serializers import ArticleSerializer
from drf_yasg.utils import swagger_auto_schema
class ArticleList(APIView):
def get(self, request, format=None):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
@swagger_auto_schema(request_body=ArticleSerializer)
def post(self, request, format=None):
serializer = ArticleSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
위 코드처럼 from drf_yasg.utils import swagger_auto_schema 과 @swagger_auto_schema(request_body=ArticleSerializer) 를 추가하고 서버를 실행하면 swagger 창에서도 게시글을 작성할 수 있다. 또한 api정보를 이전보다 자세하게 띄워준다!!
fetch 관련 자료 : https://developer.mozilla.org/ko/docs/Web/API/Fetch_API/Using_Fetch
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>프론트엔드</title>
<script src="index.js"></script>
</head>
<body>
<h1>프론트엔드</h1>
<div id="articles">
</div>
</body>
</html>
console.log("자바스크립트!")
window.onload = async function loadArticles(){
const response = await fetch('http://127.0.0.1:8000/articles/', {method:'GET'})
response_json = await response.json()
console.log(response_json)
const articles = document.getElementById('articles')
response_json.forEach(element => {
const newArticle = document.createElement('div')
newArticle.innerText = element.title
articles.appendChild(newArticle)
});
}
CORS 설치!!
(1) CORS 설치
pip install django-cors-headers
(2) settings.py 에 추가
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
MIDDLEWARE = [
...,
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
...,
]
CORS_ALLOW_ALL_ORIGINS = True
같은 도메인에서 요청을 보낼때는 허용이 되어있는데 다른 도메인에서 요청을 보낼 때는 보안상의 문제로 별도의 허용이 필요하다. 이 때 CORS로 허용해주면 된다.
CORS 관련 자료 : https://github.com/adamchainz/django-cors-headers