일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- yarn
- Kafka
- truncate
- docker-compose
- Serializer
- Hive
- ELT
- 데이터 웨어하우스
- snowflake
- 데이터레이크
- 웹 스크래핑
- Django
- 데이터파이프라인
- selenium
- spark
- docker
- redshift
- Django Rest Framework(DRF)
- 알고리즘
- 데이터마트
- docker hub
- 컨테이너 삭제
- dag
- AWS
- ETL
- airflow.cfg
- 웹 크롤링
- airflow
- SQL
- dag 작성
- Today
- Total
개발 기록장
03. Python Django 프레임웍을 사용해서 API 서버 만들기(3) 본문
학습 주제: Django Rest Framework(DRF), Serializer, ModelSerializer, HTTP Methods, Class 기반의 뷰(views), Mixin, Generic API View
Django Rest Framework(DRF)
: Django기반의 RESTful API 서버 구축을 위한 라이브러리
- Serialize/Deserialize
- Serialize: 모델 인스턴스나 Queryset과 같은 데이터를 JSON 형식으로 변환하는 과정
- Deserialize: JSON 형식 데이터를 정의된 포맷에 맞추어 다시 모델 인스턴스로 변환하는 과정
- polls_api/serializers.py
- serializers.Serializer
from rest_framework import serializers
from polls.models import Question
#Serializer 상속
class QuestionSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
question_text = serializers.CharField(max_length=200)
pub_date = serializers.DateTimeField(read_only=True)
def create(self, validated_data):
return Question.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.question_text = validated_data.get('question_text', instance.question_text)
instance.save()
return instance
- polls_api/serializers.py
- serializers.ModelSerializer
- serializers.Serializer 보다 코드 간결
from rest_framework import serializers
from polls.models import Question
#ModelSerializer
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = ['id','question_text', 'pub_data']
HTTP Methods
: HTTP의 동사(CRUD 수행)
: 주어진 리소스에 수행하길 원하는 동작
- GET
- 데이터 조회(Read)
- polls_api/views.py
- 질문 리스트 나열
- @api_view(): 인자가 아무것도 없으면 GET
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework.response import Response
from rest_framework.decorators import api_view
@api_view()
def question_list(request):
questions = Question.objects.all()
serializer = QuestionSerializer(questions, many = True)
return Response(serializer.data)
- polls_api/urls.py
- ex) http://127.0.0.1:8000/rest/question/
from django.urls import path
from .views import *
urlpatterns = [
path('question/', question_list, name='question-list')
]
- mysite/urls.py
- http://127.0.0.1:8000/rest/ 까지 include
from django.urls import include, path
from django.contrib import admin
urlpatterns = [
path('admin/', admin.site.urls),
path('polls/', include('polls.urls')),
path('rest/', include('polls_api.urls')), #추가
]
- POST
- 데이터 생성(Create)
- polls_api/views.py
- 질문 생성
- @api_view(['GET','POST']): 하나의 함수로 GET, POST 모두 수행
- 조건문으로 GET, POST 구분
from rest_framework.decorators import api_view
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework.response import Response
from rest_framework import status
@api_view(['GET','POST']) #POST 추가
def question_list(request):
#GET 조건절: Read
if request.method == 'GET':
questions = Question.objects.all()
serializer = QuestionSerializer(questions, many = True)
return Response(serializer.data)
#POST 조건절 추가: Create
if request.method == 'POST':
serializer = QuestionSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED) #생성 성공 201
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) #실패 400
- PUT/ DELETE
- PUT: 데이터 업데이트(Update)
- DELETE: 데이터 삭제(Delete)
- polls_api/views.py
- 상세(detail) 페이지에서 질문 수정 및 삭제
- @api_view(['GET','PUT','DELETE]): 하나의 함수로 GET, PUT, DELETE 모두 수행
- 조건문으로 GET, PUT, DELETE 구분
from django.shortcuts import get_object_or_404
@api_view(['GET', 'PUT', 'DELETE'])
def question_detail(request, id):
question = get_object_or_404(Question, pk=id)
#GET 조건절: Read
if request.method == 'GET':
serializer = QuestionSerializer(question)
return Response(serializer.data)
#PUT 조건절: Update
if request.method == 'PUT':
serializer = QuestionSerializer(question, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#DELETE 조건절L Delete
if request.method == 'DELETE':
question.delete()
return Response(status=status.HTTP_204_NO_CONTENT) #삭제 성공 204
- polls_api/urls.py
- ex) http://127.0.0.1:8000/rest/question/1/
from django.urls import path
from .views import *
urlpatterns = [
path('question/', question_list, name='question-list'),
path('question/<int:id>/', question_detail, name='question-detail') #추가
]
코드 변형
: 코드를 다양한 방식으로 변형시켜 단순화하고, 기능은 유지한다.
- Class 기반의 뷰(views)
- Class안에 각 기능을 함수로 구현
- polls_api/views.py
- 각 페이지를 이루는 class안에 함수로 기능 정의
- APIView 사용
from rest_framework.views import APIView
#질문 리스트
class QuestionList(APIView):
#GET: Read
def get(self, request):
questions = Question.objects.all()
serializer = QuestionSerializer(questions, many=True)
return Response(serializer.data)
#POST: Create
def post(self, request):
serializer = QuestionSerializer(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 QuestionDetail(APIView):
#GET: Read
def get(self, request, id):
question = get_object_or_404(Question, pk=id)
serializer = QuestionSerializer(question)
return Response(serializer.data)
#PUT: Update
def put(self, request, id):
question = get_object_or_404(Question, pk=id)
serializer = QuestionSerializer(question, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#DELETE: Delete
def delete(self, request, id):
question = get_object_or_404(Question, pk=id)
question.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
- polls_api/urls.py
- .as_view(): 각 클래스 기존의 함수처럼 URL을 통해 실행
- 질문 리스트: ex) http://127.0.0.1:8000/rest/question/
- 상세 페이지: ex) http://127.0.0.1:8000/rest/question/1/
from django.urls import path
from .views import *
urlpatterns = [
path('question/', QuestionList.as_view(), name='question-list'),
path('question/<int:id>/', QuestionDetail.as_view(), name='question-detail'),
]
- Mixin
- polls_api/views.py
- 각 페이지를 이루는 class안에 함수로 기능 정의
- 위의 Class에서 함수를 모두 구현하는 방식보다 코드 간소화
- 기능들이 구현되어있는 mixins 상속
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework import mixins
from rest_framework import generics
class QuestionList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class QuestionDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
- polls_api/urls.py
- .as_view(): 각 클래스 기존의 함수처럼 URL을 통해 실행
- <int: pk>로 꼭 작성해야함 (<int: id> 불가)
- 질문 리스트: ex) http://127.0.0.1:8000/rest/question/
- 상세 페이지: ex) http://127.0.0.1:8000/rest/question/1/
from django.urls import path
from .views import *
urlpatterns = [
path('question/', QuestionList.as_view(), name='question-list'),
path('question/<int:pk>/', QuestionDetail.as_view(), name='question-detail'),
]
- Generic API View
- 공식 문서: https://www.django-rest-framework.org/api-guide/generic-views/
Generic views - Django REST framework
www.django-rest-framework.org
- polls_api/views.py
- ListCreateAPIView: GET, POST method handlers
- RetrieveUpdateDestroyAPIView: GET, PUT, DELETE,(...PATCH) method handlers
- 기능들이 구현되어있는 generics 이용
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework import generics
class QuestionList(generics.ListCreateAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
class QuestionDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
Rest Framework 오류
: django.template.exceptions.TemplateDoesNotExist: rest_framework/api.html
- Rest Framework 오류 메시지
- Rest Framework 템플릿이 존재하지 않는다는 오류
- 해결책
- Rest Framework 설치 확인: 템플릿이 존재하지 않는다는 오류
- Rest Framework 설치 확인
- pip freeze 명령어로 설치 확인: djangorestframework==3.15.1 이런식으로 나와 있음
pip freeze
- 설치가 되어 있지 않은 경우:
pip install djangoresframework
- Rest Framework 설치되어 있는데도 오류가 나는 경우
- settings.py에 rest_framework 추가
# Application definition
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', #추가
]
- 정상 작동 화면
- ex) http://127.0.0.1:8000/rest/question/
공부하며 느낀점
Mixin과 Generic API View를 사용해서 코드를 간소화하면서, 개발자가 꾸준히 더 좋은 코드를 위해 공부해야 하는 이유를 깨달았다.
'데브코스(DE) > 장고 활용한 API 서버 제작' 카테고리의 다른 글
05. Python Django 프레임웍을 사용해서 API 서버 만들기(5) (0) | 2024.04.12 |
---|---|
04. Python Django 프레임웍을 사용해서 API 서버 만들기(4) (0) | 2024.04.11 |
02. Python Django 프레임웍을 사용해서 API 서버 만들기(2) (0) | 2024.04.09 |
01. Python Django 프레임웍을 사용해서 API 서버 만들기(1) (0) | 2024.04.08 |