스파르타 코딩클럽 내일배움캠프 AI 웹개발자양성과정 3회차
2022.10.25. 38일차 - TIL
1. 장고 심화 원격 강의
1) 목표
DRF로 프로젝트 세팅하기시리얼라이저의 의미와 역할 이해하기시리얼라이저를 활용해 CRUD 하기포스트맨으로 DRF 개발 테스팅하기클래스형 뷰 작성하기- FETCH API를 써서 프론트엔드에서 DRF의 데이터를 가져와서 나타내기
프로젝트 세팅
1. 작업 폴더 생성
2. vscode로 오픈
3. 가상환경 만들기
$ python -m venv venv
4. 가상환경 활성화
$ \venv\scripts\activate
5. django 설치
$ pip install django
6. DRF 설치
$ pip install djangorestframework
7. 프로젝트 생성
$ django-admin startproject 프로젝트명 .
8. requirements.txt 생성
$ pip freeze > requirement.txt
9. INSTALLED_APPS에 'rest_framework' 추가
10. github에 올리기
$ git init
$ git remote add origin [원격저장소주소]
$ git branch -M main
$ git add .
$ git commit -m "커밋메시지"
$ git push origin main
시리얼라이저
우리는 앞으로 모든 데이터를 JSON 데이터로 주고받을 것이다. 굉장히 간략하고, 그냥 단순한 String이기 때문에 다양한 개발언어에서 동작할 수 있다.
일단, 앱을 생성하고, settings.py의 INSTALLED_APPS의 앱 이름을 추가한다. 그리고 model을 작성하고, makemigrations와 migrate를 한 후 admin에 해당 모델을 register해 기본 환경을 설정한다.(createsuperuser로 admin 계정에서 모델 확인 가능.. 모델에서 __str__을 통해 원하는 값을 admin row의 제목으로 사용가능하다.)
앱의 url에 경로를 입력하고, views를 작성한다. 이때 여태까지는 HttpResponse(pure django의 방식이다..)를 사용했지만 앞으로는 Response(drf django 방식이다..)를 사용하겠다.
from django.http import HttpResponse
def index(request):
if request.method == 'GET':
return HttpResponse("완성")
#####Change#####################################
from rest_framework.response import Response
from rest_framework.decorators import api_view
@api_view(['GET'])
def index(request):
return Response("완성")
이제 우리는 Response 안에 우리가 작성한 모델의 값을 불러오고 싶다. 여태까지 배운 것을 보면 아래와 같이 적을 것이다.
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
@api_view(['GET'])
def index(request):
articles = Article.objects.all() # Article 모델 row 전부 가져오기
return Response(articles)
하지만 이렇게 작성하면 JSON 데이터가 아니라고 오류 메시지가 뜬다. 흠... Rest_Framework는 JSON 데이터가 와야 하는가 보다. 그러면 이렇게 고쳐주겠다.
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
@api_view(['GET'])
def index(request):
articles = Article.objects.all() # Article 모델 row 전부 가져오기
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 데이터가 잘 전달 된 것을 확인할 수 있다. 하지만 문제가 있으니... 모델에 있는 데이터를 저렇게 하나하나 json으로 바꾸는 것은 너무 귀찮다... 그래서 이러한 과정을 자동화하기 위해 등장한 것이 바로 시리얼라이저이다!!! 시리얼라이저는 최상위 루트에 serializer.py를 만들어 작성한다.
시리얼라이저를 이용한 CRUD
serializer.py에 다음과 같은 코드를 작성한다.
from rest_framework import serializers
from articles.model import Article
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article # 시리얼라이즈할 모델
fields = "__all__" # 모든 필드를 다 다룸
그리고 views에 다음과 같이 작성한다. 아래는 한개의 데이터 일 때와 여러개의 데이터일 때의 코드이다.
from rest_framework.response import Response
from rest_framework.decorators import api_view
from articles.models import Article
from articles.serializer import ArticleSerializer
@api_view(['GET'])
def index(request):
articles = Article.objects.all() # Article 모델 row 전부 가져오기
article = articles[0] # 한개의 데이터 일 때
serializer = ArticleSerializer(article)
return Response(serializer.data)
##########################################################################
@api_view(['GET'])
def index(request):
articles = Article.objects.all() # Article 모델 row 전부 가져오기
# 다수의 데이터 일 때
# 여러개의 데이터를 serializer할 것이라 표현
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
시리얼라이저를 이용해 데이터를 읽고(GET방식), 데이터를 생성(POST방식)해보자. 이때 주의할 것은 여태까지 우리는 form_data 형식으로 데이터를 생성했다는 것이다. 앞으로는 json으로 데이터를 생성한다.
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.serializer import ArticleSerializer
@api_view(['GET', 'POST'])
def index(request):
# 데이터 읽기(READ)
if request.method == 'GET':
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True) # json -> data
return Response(serializer.data)
# 데이터 생성하기(CREATE)
elif request.method == 'POST':
serializer = ArticleSerializer(data=request.data) # data -> json
if serializer.is_valid(): # 데이터의 유효성 검사
serializer.save() # 데이터 저장
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
그러면 이제 상세페이지, 업데이트, 삭제 코드를 완성해보자.
#urls.py
...
urlpatterns = [
...
path("<int:article_id>/", view.article_view, name="article_view"),
]
#views.py
...
from rest_framework.generics import get_object_or_404
# 상세페이지GET, 업데이트PUT, 삭제DELETE
@api_view(['GET', 'PUT', 'DELETE'])
def article_view(request, article_id):
# 특정 게시물 상세히 읽어오기
if request.method == 'GET':
# article = Article.objects.get(id=article_id)
# 해당 article_id 인스턴스 가져옴
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article)
return Response(serializer.data)
# 특정 게시물 수정하기
elif request.method == 'PUT':
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)
# 특정 게시물 삭제하기
elif request.method == 'DELETE':
article = get_object_or_400(Article, id=article_id)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
포스트맨으로 API 확인하기
원하는 기능들을 포스트맨에 세팅해 놓으면 테스트할 때 편리하다. 그리고 몇가지 주의하자면,
- json 데이터는 Body > raw > JSON으로 세팅 후 입력해야 정상적으로 보내진다
- Environments > Create Environment > local 입력 > VALUEABLE에 host, INITIAL VALUE와 CURRENT VALUE에 http://127.0.0.1:8000을 입력 > Environment을 loca로 변경 > {{host}}/url하위주소로 대체 가능
Swagger
API Spec 문서를 자동화 해주는 소프트웨어
$pip install drf-yasg 설치
INSTALLED_APPS에 'drf_yasg' 추가
urls.py 수정(공식문서 참고)
클래스형 View
함수형보다 클래스형이 이후에 상속 등의 면에서 다양한 기능들을 수행할 수 있다.
@api_view(['GET', 'POST'])
def index(request):
# 데이터 읽기(READ)
if request.method == 'GET':
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True) # json -> data
return Response(serializer.data)
# 데이터 생성하기(CREATE)
elif request.method == 'POST':
serializer = ArticleSerializer(data=request.data) # data -> json
if serializer.is_valid(): # 데이터의 유효성 검사
serializer.save() # 데이터 저장
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
###################################################################################
from rest_framework.views import APIView
class ArticleView(APIView):
def get(self, request, format=None):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True) # json -> data
return Response(serializer.data
def post(self, request, format=None):
serializer = ArticleSerializer(data=request.data) # data -> json
if serializer.is_valid(): # 데이터의 유효성 검사
serializer.save() # 데이터 저장
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'PUT', 'DELETE'])
def article_view(request, article_id):
# 특정 게시물 상세히 읽어오기
if request.method == 'GET':
# article = Article.objects.get(id=article_id)
# 해당 article_id 인스턴스 가져옴
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article)
return Response(serializer.data)
# 특정 게시물 수정하기
elif request.method == 'PUT':
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)
# 특정 게시물 삭제하기
elif request.method == 'DELETE':
article = get_object_or_400(Article, id=article_id)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
#############################################################################
class ArticleDetailView(APIView):
def get(self, request, article_id, format=None):
article = get_object_or_404(Article, id=article_id)
serializer = ArticleSerializer(article)
return Response(serializer.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)
def delete(self, request, article_id, format=None):
article = get_object_or_400(Article, id=article_id)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Fetch API
일단 패스... 너무 어렵다...
***데코레이터 function
주로 @로 많이 표현이 되는데 정확한 동작 원리를 이해해보자.
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()
###########Change########################
def wrapper_function(func):
def decorated_function:
print("함수 이전에 실행")
func()
print("함수 이후에 실행")
return decorated_function
@wrapper_function
def basic_function():
print("실행하고자 하는 함수")
basic_function()
###########Result###########################
'''
함수 이전에 실행
실행하고자 하는 함수
함수 이후에 실행
'''
결국 저 새로운 함수에 기존 함수를 넣어 만드는 것을 저렇게 표현할 수 있는 것 같다.
***JSON
서버와 서버, 서버와 클라이언트 간 데이터 전송에 사용하는 데이터 형식
ajax의 발달로 전체 화면 렌더링이 아닌 필요한 부분만 데이터 전송 가능
키값에 따옴표
Serialization : Key-Value 자료 형태를 JSON 형태로 변환
Deserialization : JSON 형태를 Key-Value 자료 형태로 변환
파싱 : 데이터의 의미 해석, 더 넓은 의미
참고자료
https://www.django-rest-framework.org/tutorial/3-class-based-views/
https://drf-yasg.readthedocs.io/en/stable/readme.html
https://developer.mozilla.org/ko/docs/Web/API/Fetch_API/Using_Fetch
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
'개발일지 > AI 캠프' 카테고리의 다른 글
내일배움캠프 AI - 40일차 TIL, 2022.10.27 (0) | 2022.10.28 |
---|---|
내일배움캠프 AI - 39일차 TIL, 2022.10.26 (0) | 2022.10.26 |
내일배움캠프 AI - 37일차 TIL, 2022.10.24 (0) | 2022.10.25 |
내일배움캠프 AI - 8주차 WIL (0) | 2022.10.23 |
내일배움캠프 AI - 36일차 TIL, 2022.10.21 (0) | 2022.10.23 |