Serializer
Django Shell에서 Serializer 사용하기
ModelSerializer
GET
HTTP Methods
POST
PUT / DELETE
Class 기반의 뷰
Mixin
Generic API View
DRF(Django Rest Framework)에서 제공하는 기능
pip3 install djangorestframework
Serialize와 Deserialize의 기능
Serialize: 모델 인스턴스나 QuerySet과 같은 데이터를 JSON 형식의 파일로 변환하는 작업
Deserialize: JSON 형식의 데이터를 정의된 포맷에 맞춰 다시 모델 인스턴스로 변환하는 작업
OrderedDict: 저장된 key-value 쌍의 순서를 보장하는 딕셔너리
.get
("requested_data", replace_data): 요청한 데이터가 있을 경우 해당 데이터를, 없을 경우 두 번째 인자로 주어지는 대체값을 반환polls_api/serializers.py
from rest_framework import serializers
from polls.models import Question
class QuestionSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only = True)
question_text = serializers.CharField(max_length = 200)
pub_date = serializers.DateTimeField(read_only = True)
# 유효성 검사를 통과한 JSON(OrderedDict) 형태의 데이터를 기반으로 생성
def create(self, validated_data):
return Question.objects.create(**validated_data)
def update(self, instance, validated_data):
# question_text라는 key가 없을 경우, 두 번째 인자로 주어지는 대체값을 사용
instance.question_text = validated_data.get("question_text", instance.question_text)
instance.save()
return instance
Serialize
QuestionSerializer(question)
: Question 객체를 Serialize
JSONRenderer().render(serializer.data)
: Serialize된 데이터를 JSON 형식으로 렌더링
Deserialize
data = json.loads(json_str)
: JSON 형식의 데이터를 딕셔너리 형태로 Deserialize
serializer = Serializer(data = data)
serializer.is_valid()
: 유효성 검사
serializer.save()
: Serializer 객체의 create() 혹은 update() 메서드 호출
serializers.Serializer 대신 serializers.ModelSerializer를 상속해 더 간결하게 구현
polls_api/serializers.py
...
class QuestionSerializer(serializers.ModelSerializer):
# 메타 정보 기록
class Meta:
model = Question
fields = ["id", "question_text", "pub_date"]
정보를 조회하는 기능을 구현
project/urls.py
...
urlpatterns = [
...
path('rest/', include('polls_api.urls')),
]
polls_api/urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('question', question_list, name = "question-list"),
]
polls_api/views.py
...
from rest_framework.decorators import api_view
from rest_framework.response import Response
from polls.models import Question
from polls_api.serializers import QuestionSerializer
# decorator를 사용해 GET 요청을 처리하는 api view임을 명시
@api_view()
def question_list(request):
questions = Question.objects.all()
# many 옵션을 통해 객체 리스트를 인자로 사용 가능
serializer = QuestionSerializer(questions, many = True)
return Response(serializer.data)
TemplateDoesNotExist 에러 발생
리소스: 기능 혹은 모델
CRUD에 대응
GET(Read): 특정 리소스 표시 요철
POST(Create): 특정 리소스에 엔티티를 제출
PUT(Update): 특정 리소스의 내용 수정
DELETE(Delete): 특정 리소스 삭제
HTTP Status Code
polls_api/views.py
...
@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)
elif request.method == "POST":
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)
polls_api/views.py
from django.shortcuts import render, get_object_or_404
...
@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)
elif request.method == "PUT":
serializer = QuestionSerializer(question, 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)
elif request.method == "DELETE":
question.delete()
return Response(status = status.HTTP_204_NO_CONTENT)
뷰를 메서드가 아닌 클래스 기반으로 정의
polls_api/views.py
...
from rest_framework.views import APIView
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, 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 = [
path('question', QuestionList.as_view(), name = "question-list"),
path('question/<int:id>/', QuestionDetail.as_view(), name = "question-detail"),
]
Mixin 클래스를 상속해 기존과 같은 기능을 더 간결하게 구현
polls_api/views.py
from rest_framework import status, mixins, 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
...
urlpatterns = [
...
path('question/<int:pk>/', QuestionDetail.as_view(), name = "question-detail"),
]
Generic 클래스들을 사용해 더욱 더 간결하게 구현
from rest_framework import generics
from polls.models import Question
from polls_api.serializers import QuestionSerializer
class QuestionList(generics.ListCreateAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
class QuestionDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Question.objects.all()
serializer_class = QuestionSerializer