Serializer와 Views
- Django Shell에서 Serializer 사용
- ModelSerializer
- HTTP Request Method
- GET, POST, PUT, DELETE
- Class 기반의 Views
- Mixin
- Generic API View
Serialize
모델 인스턴스나 QuerySet과 같은 데이터들을 API로 주고 받기 위해서 JSON 파일의 형식으로 변환하는 작업
Deserialize
JSON 형식의 데이터들을 정의된 포맷에 맞추어 다시 모델 인스턴스로 변환하는 작업
Serializer
위와 같은 변환과정을 담당하는 매개체,
모델에 있는 데이터를 json 데이터로 변환하고 json 데이터를 모델을 통해 테이블에 저장하는 역할을 함
polls_api App 추가
python manage.py startapp polls_api
polls_api.serializers.py 생성
from rest_framework import serializers
# polls의 모델을 불러옴
from polls.models import Question
# Question 모델에 있는 필드들을 Serialize하기 위해선
# 각 필드들을 매칭시켜주는 작업을 해야함
# 단, 어떤 필드들을 Serializer 내부에 적어주지 않는다면,
# 해당 필드에 있는 데이터는 Serialize되지않음
class QuestionSerializer(serializers.Serailizer):
id = serializers.IntegerField(read_only=True)
question_text = serializers.CharField(max_length=200)
pub_date = serializers.DateTimeField(read_only=True)
# serializer는 생성할 때, 유효성 검사를 통과한 데이터를 기반으로 저장(validated_data)
def create(self, validated_data) :
# validated_date를 기반으로 Question을 생성
return Question.objects.create(**validated_data)
# 받아온 instance에 validated_data를 이용해서 업데이트
def update(self, instance, validated_data):
# question_text가져와서 instance에 넣어줌
# validated_data에 값이 없으면 원래 값을 유지해라
instance.question_text = validated_data.get('question_text',instance.question_text)
instance.save()
return instance
.get(key_name)은 {key:value}에서 key값에 맞는 value를 반환하는 함수from polls.models import Question
from polls_api.serializers import QuestionSerializer
# Serialization
# 모델을 Dictionary 형식으로 변환
q = Question.objects.first()
serializer = QuestionSerializer(q)
serializer.data
# String 형태의 JSON으로 변환
#json 형태를 바꾸기 위해선 JSONRenderer가 필요
from rest_framework.renderers import JSONRenderer
json_str = JSONRenderer().render(serializer.data)
json_str
# Deserialization
# JSON에서 Dictionary로 변환
import json
data = json.loads(json_str)
# serializer.data와 동일해졌음을 확인
data
# 모델을 만들기 위해 새로운 serializer를 생성
# dictionary를 모델로 변환
serializer = QuestionSerializer(data=data)
# 유효성 검증, 필수
serializer.is_valid()
# save()시, 만들어진 instance가 없다면 create
# instance가 있다면 update를 진행
# 이 경우 create가 동작.
new_question = serializer.save()
# update
data = {'question_text':'제목 수정'}
serializer = QuestionSerializer(new_question, data=data)
serializer.is_valid()
# new_question이란 instance가 있으므로 update 진행
serializer.save()
# validation이 통과하지 않는 상황
long_text = "abcd"*300
data = {'question_text' : long_text}
serializer = QuestionSerializer(data=data)
# False
serializer.is_valid()
# 원인 확인
serializer.errors
# field가 최대치인 200을 초과했기에 발생
Serializer가 아닌 ModelSerializer로 단순화
polls_api.serializers.py 수정
from rest_framework import serializers
from polls.models import Question
class QuestionSerializer(serializers.ModelSerializer):
# create, update가 자동으로 생성되어 작동
class Meta:
model = Question
fields = ['id','question_text','pub_date']
[참고 웹사이트]
CRUD 기능을 구현하는 HTTP 메서드
데이터 생성(Create) : POST
데이터 조회(Read) : GET
데이터 업데이트(Update) : PUT
데이터 삭제(Delete) : DELETE
-> 사용자의 입장에서 생각하는 것이 바람직함
( POST와 PUT이 혼동될 수 있음 )
HTTP에서 정보를 조회하는 메소드 : GET
정보를 조회하지않고 새로운 데이터를 만드는 메소드 : POST
rest_framework 설치
py -m pip install djangorestframework
settings.py에 등록...
INSTALLED_APPS = [
'rest_framework',
...
]polls_api.views.py
from django.shortcuts import render
# api_view : 메소드를 정의할 때 사용
from rest_framework.decorators import api_view
from rest_framework.response import Response
from polls.models import Question
from polls_api.serializers import QuestionSerializer
# Question의 목록 구현
# @api_view() : question_list가 get요청을 처리할 것이다.
@api_view()
def question_list(request) :
questions = Question.objects.all()
# 여러 개의 instance를 serializer에 줄 때는 many옵션을 사용
serializer = QuestionSerializer(questions, many = True)
return Response(serializer.data)
polls_api.urls.py 생성
from django.urls import path
from .views import *
urlpatterns = [
path('question/',question_list, name='question-list')
]
urls.py에 등록
urlpatterns = [
path('admin/', admin.site.urls),
path('polls/', include('polls.urls')),
path('rest/', include('polls_api.urls')),
]

-> 실제론 Json 형식으로 요청으로 이루어짐,
Django가 api로 받은 Json을 가시화한 것
polls_api.views.py
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework import status
# @api_view(['GET','POST']) : get, post 요청을 둘다 처리함
@api_view(['GET','POST'])
def question_list(request) :
if request.method == 'GET':
questions = Question.objects.all()
serializer = QuestionSerializer(questions, many = True)
return Response(serializer.data)
# post일 경우, 요청의 data를 받아와 새로운 question으로 만들어줌
if request.method == 'POST':
serializer = QuestionSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
# 보다 명확하게 생성이 되었다는 status를 전달
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
# 잘못된 응답에 대해서 400 BAD request를 출력
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
CREATE TEST


polls_api.views.py
from django.shortcuts import render, get_object_or_404
from rest_framework.decorators import api_view
from rest_framework.response import Response
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework import status
...
@api_view(['GET','PUT','DELETE'])
def question_detail(request, id):
question = get_object_or_404(Question, pk=id)
if request.method == 'GET':
serializer = QuestionSerializer(question)
return Response(serializer.data)
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)
if request.method == "DELETE" :
question.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Class 기반의 Api_view로 변환
장점
코드가 잘 정리됨
Django rest_framework에서 제공하는 다양한 class들을 활용해서 반복되는 코드를 작성할 필요 없이 쉽게 views를 만들 수 있다.
class는 상속을 받을 수 있음
polls_api.views.py
from django.shortcuts import render, get_object_or_404
from rest_framework.decorators import api_view
from rest_framework.response import Response
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework import status
# class 기반 api_view
from rest_framework.views import APIView
# if 문을 사용하지 않고 method로 더 확실하게 분리
class QuestionList(APIView):
def get(self, request):
questions = Question.objects.all()
serializer = QuestionSerializer(questions, many = True)
return Response(serializer.data)
def post(self, request):
serializer = QuestionSerializer(data=request.data)
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)
class QuestionDetail(APIView):
def get(self, request, id):
question = get_object_or_404(Question, pk=id)
serializer = QuestionSerializer(question)
return Response(serializer.data)
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)
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
from django.urls import path
from .views import *
urlpatterns = [
# as_view가 요청을 받으면 QuestionList의 인스턴스를 생성
path('question/', QuestionList.as_view() , name='question-list'),
path('question/<int:id>/', QuestionDetail.as_view(),name="queston-detail"),
]
Mixin을 사용하여 코드를 더욱 간단화
polls_api.views.py
from django.shortcuts import render, get_object_or_404
from rest_framework.decorators import api_view
from rest_framework.response import Response
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework import status, mixins, generics
from rest_framework.views import APIView
# ListModelMixin -> GET에서 활용
# CreateModelMixin -> POST에서 활용
class QuestionList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
def get(self, request, *args, **kwargs):
# list 호출, list 메소드는 ListModelMixin에 정의되어있음
# 받은 값을 그대로 전달
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):
# pk를 받을 때, QuestionDetail이 실행되므로
# 단일 객체가 아닌 Question.objects.all()을 사용하더라도 내부적으로 처리가 됨
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.destory(request, *args, **kwargs)
polls_api.urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('question/', QuestionList.as_view() , name='question-list'),
# GenericAPIView에서 primary key를 pk로 받기 때문에, pk라 해줘야함
path('question/<int:pk>/', QuestionDetail.as_view(),name="queston-detail"),
]
Generic API를 사용하여 코드를 더더욱 간단화
polls_api.views.py
from polls.models import Question
from polls_api.serializers import QuestionSerializer
from rest_framework import generics
# class 안에서 기능이 전부 구현이 되어있기 때문에, 이를 상속받아 사용
class QuestionList(generics.ListCreateAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
class QuestionDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
class를 통해 기능을 상속 받았기에 코드가 훨씬 간결해졌음을 확인할 수 있다.