2022. 3. 22. 16:02ㆍ강의 정리/Django REST Framework
장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생각이 있으신 분은 위 출처의 강의를 적극 추천드립니다!!!
Django JSON 직렬화(Serialization)
직렬화(serialization)
_모든 프로그래밍 언어의 통신에서 데이터는 필히 문자열로 표현되어야만 합니다.
- 송신자(백엔드) : 객체를 문자열로 변환하여, 데이터 전송 -> 직렬화
- 수신자(프론트엔드) : 수신한 문자열을 다시 객체로 변환하여, 활용 -> 비직렬화
_각 언어에서 모두 지원하는 직렬화 포맷 (JSON, XML 등)이 있고, 특정 언어에서만 지원하는 직렬화 포맷이 있습니다.
ex) 파이썬의 Pickle
JSON 변환
데이터는 같지만, 응답 형식이 다를 수는 있습니다.
_보통의 웹에서는 GET 요청에 대해 HTML 포맷으로 응답하고, POST 요청을 application/x-www-form-urlencoded 인코딩으로 요청하고, HTML 포맷으로 응답합니다.
_요즘의 API 서버에서는 대부분 JSON 인코딩으로 요청 / 응답합니다.
JSON 포맷과 PICKLE 포맷
JSON 포맷
- 다른 언어 / 플랫폼과 통신할 때 주로 사용
- 표준 라이브러리 json 제공 // 파이썬 기본 타입에 대해서는 지원을 하지만, Django나 커스텀 타입은 지원을 제공하지않음.
- pickle에 비해서 직렬화를 지원하는 데이터 타입의 수가 적지만, 커스텀 Rule도 지정 가능
https://www.w3schools.com/python/python_json.asp
Pickle 포맷
- 파이썬 전용 포맷으로서 파이썬 시스템끼리만 통신할 때 사용 가능
- 표준 라이브러리 pickle 제공 -> json 라이브러리가 유사한 사용 방법
- 주의) 파이썬 버전 특성을 타는 경우가 있습니다
https://wayhome25.github.io/cs/2017/04/04/cs-04/
_ json / pickle 모두 파이썬 기본 라이브러리로 제공이 됩니다.
그러나 장고 타입 (Model / QuerySet 등)에 대해서는 직렬화 Rule이 없습니다. -> 오류 발생
_ 그러면 어떻게 해결 할 수 있을까요? -> 직접 변환하는 방법이 있습니다.
QuerySet을 JSON 형식으로 직접 바꿔준 다음 json.dumps를 통해 json으로 써줍니다.
data = [
{'id': post.id, 'title':post.title, 'content': post.content}
for post in Post.objects.all()
]
json.dumps(data, ensure_ascii=False).encode('utf8') # ensure_ascii에 False값을 주면, json.dumps()값을 UTF-8로 수동으로 인코딩할 수 있다.
_DjangoJSONEncoder를 통해 아래 타입들에 대한 Rule을 추가로 구현할 수 있습니다.
- datetime.datetime, datetime.date, datetime.time, datetime.delta
- decimal.Decimal, uuid.UUID, Promise
import json
from django.core.serializers.json import DjangoJSONEncoder
_ 그러나 매번 직접 변환하기는 너무 번거로우니 -> 직접 변환 Rule을 지정하거나 DRF의 JSONRender, DRF의 serializers.py를 이용하는 방법들이 있습니다. -> 그러나 이러한 방법들을 Model에 대한 변환 Rule은 지원하지 않습니다 ㅠㅠ
ModelSerializer를 통한 JSON 직렬화
_Serializer / ModelSerializer은 Form / ModelForm과 유사합니다.
-> 역할 면에서 Serializer은 POST 요청만 처리하는 Form
- 둘의 공통점
- 폼 필드 지정 혹은 모델로부터 읽어오기.
- 입력된 데이터에 대한 유효성 검사를 통해 저장합니다.
- 둘의 차이점
- Form / ModelForm : Form태그가 포함된 HTML을 생성합니다.
- Serializer / ModelSerializer : Form 데이터가 포함된 JSON 문자열을 생성합니다.
_ModelSerializer
from rest_framework.serializers import ModelSerializer
# Post모델에 대한 ModelSerializer 정의
class PostSerializer(ModelSerializer):
class Meta:
model = Post
fields = '__all__'
post = Post.objects.first() # Post 타입
serializer = PostSerializer(post)
serializer.data # -> ReturnDict 타입
https://www.django-rest-framework.org/api-guide/serializers/
_ Model 객체나 쿼리셋에 대해 ReturnDict type으로 변환 할 수 있습니다.
from .serializers import PostSerializer
from .models import Post
# 한개의 모델만 넘기기
serializer = PostSerializer(Post.objects.first())
serializer.data # {'id': 1, 'message': '첫번째 포스팅' ... }
# 쿼리셋을 넘기기
serializer = PostSerializer(Post.objects.all(), many=True)
serializer.data # [OrderDict([('id', 1), ...)]), OrderDict([('id': 2), ...)]) ...]
_ Model 객체에 대해서는 필히 many=False(디폴트)를 지정해주어야 하고,
쿼리셋 객체에 대해서는 필히 many=True를 지정해주어야 합니다.
-> 지정이 맞지 않으면 변환 에러가 발생하게 됩니다.
View에서의 JSON 응답
모든 View는 HttpResponse 타입의 응답을 해야 하고, 일반적으로 다음 2가지 방법을 사용합니다.
- 직접 json.dumps를 통해 직렬화된 문자열을 획득하여, HttpResponse를 통해 응답합니다.
- 1번을 정리하여 JsonResponse를 지원합니다.
DRF를 통한 JSON 응답
DRF Response를 활용합니다.
qs = Post.objects.all()
serializer = PostModelSerializer(qs, many=True)
from rest_framework.response import Response
response = Response(serializer.data) # Content-type : text/html이 디폴트 지정
_ Response에서는 "JSON 직렬화" 가 Lazy하게 동작합니다. 실제 응답 생성시에 .rendered_content 속성에 접근하며, 이 때 변환이 이루어집니다.
Response와 APIView
_ DRF의 모든 뷰는 APIView를 상속 받습니다. APIView를 통해서 Response에 다양한 속성이 지정됩니다.
from rest_framework.views import APIView
renderer_cls = APIView.renderer_classes[0]
renderer_obj = renderer_cls()
response.accepted_renderer = renderer_obj # JSON 변환을 위한 JSONRenderer 인스턴스
response.accepted_media_type = renderer_obj.media_type # 'application/json'
response.renderer_context = {'view': None, 'args': (), 'kwargs': {}, 'request': None}
response # <Response status_code=200, "application/json">
실제 DRF Serializer 사용
#views.py
from rest_framework import generics
class PostListAPIView(generics.ListAPIView): # 만약 list, create, detail, update, delete등을 모두 사용하려면 ViewSet을 이용
queryset = Post.objects.all()
serializer_class = PostSerializer
post_list = PostListAPIView.as_view()
#urls.py
urlpatterns = [
path('public/', views.PostListAPIView.as_view()),
]
포스팅 조회 응답에 username 응답을 하려면?
_ author = FK(User) 필드가 있을 때, Serializer에서는 FK 키값으로 응답
serializer.ReadOnlyField를 통해서 FK의 필드값을 읽어 올 수 있습니다.
#models.py
from django.conf import settings
from django.db import models
# Create your models here.
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
message = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
#serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
username = serializers.ReadOnlyField(source='author.username') # 추가
class Meta:
model = Post
fields = ['pk', 'username', 'title', 'cotnent'] # 'username' 추가
_ 또는 StringRelatedField, SlugRelatedField 등 뿐만 아니라, 중첩된 Serializer를 통해서도 구현 가능합니다.
#serializers.py
from django.contrib.auth import get_user_model
from rest_framework import serializers
from .models import Post
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ['username']
class PostSerializer(serializers.ModelSerializer):
author = AuthorSerializer()
class Meta:
model = Post
fields = '__all__'
도움 받은 글들
https://sss20-02.tistory.com/65
https://brownbears.tistory.com/82
'강의 정리 > Django REST Framework' 카테고리의 다른 글
DRF ViewSet과 Router (0) | 2022.07.13 |
---|---|
DRF mixins 상속을 통한 APIView (0) | 2022.07.12 |
DRF로 APIView, Json 응답뷰 만들기 (0) | 2022.07.11 |
Django JSON 응답뷰 (0) | 2022.03.12 |
Django API와 REST (0) | 2022.03.10 |