[Django Rest Framework] 직렬화(Serializer)에 대해서 알아보자

Donnis Dev-note
6 min readMar 11, 2020

직렬화

모든 프로그래밍 언어의 통신에서 데이터는 필히 문자열로 표현되야 합니다.
송신자 : 객체를 문자열로 변환하여 전송 -> 직렬화
수신자 : 수신한 문자열을 다시 객체로 변환하여, 활용 -> 비직렬화

각 언어에서 모두 지원하는 직렬화 포맷(JSON, XML 등) 과 특정언어에서만 지원하는 직렬화 포맷 (Python의 Pickle) 이 있습니다.

요즘의 API서버에서는 대개 JSON 인코딩된 요청/응답 사용을 합니다.

JSON 포맷

  • 다른 언어/ 플랫폼과 통신할 때 주로 사용
  • 표준 라이브러리 json 제공
  • pickle에 비해 직렬화를 지원하는 데이터 타입 수가 적지만, 커스텀 Rule 지원도 가능합니다.
import jsonpost_list=[{'message': 'hello'},]#직렬화
json_string = json.dumps(post_list)
print(json_string) # [{'message': 'hello'},]
#비직렬화
print(json.loads(json_string))

Pickle 포맷

  • 파이썬 전용 포맷으로써 파이썬 시스템 끼리만 통신할 때 사용 가능합니다.
  • 표준 라이브러리 pickle 제공.
import picklepost_list=[{'message': 'hello'},]pickle_bytes = pickle.dumps(post_list)
print(pickle_bytes) # b'\x80\0x3]q\x00........
print(pickle.loads(pickle_bytes))

json/pickle 모두 파이썬 기본 라이브러리이며 장고의 Model, QuerySet 등에 대해서는 직렬화 Rule이 없기때문에 그대로 dumps()에 넣으면 에러가 발생합니다. (TypeError: Object of type QuerySet is not JSON serializable)

rest_framework.renderer.JSONRender

rest_framework/utils/encoders.py 의 JSONEncoder를 통한 직렬화 지원

  • __getitem__ 속성 지원시 dict(obj) 변환
  • __iter__ 속성 지원시 tuple 변환
  • QuerySet 타입일 시 tuple 변환
  • .tolist 속성 지원 시 obj.tolist()

Model 타입은 미지원 -> ModelSerializer를 통해 변환이 가능합니다.

rest_framework.renderers.JSONRenderer

json.dumps에 대한 래핑 클래스 -> 보다 편리한 직렬화를 지원

from rest_framework.renderers import JSONRendererdata = Post.objects.all()
JSONRenderer().render(data)
# 하지만 Model에 대한 변환 Rule은 아직 없음.

ModelSerializer를 통한 JSON 직렬화

Serializer/ModelSerializer는 Form/ModelForm과 유사합니다.
=> 역할 면에서 Serializer는 POST 요청만 처리하는 Form임.

장고 기본 View에서의 HttpResponse JSON 응답

모든 View는 HttpResponse 타입의 응답을 해야만 함.

  1. 직접 json.dumps를 통해 문자열을 획득, HttpResponse를 통해 응답
  2. 1번을 정리하여 jsonResponse 지원 -> 내부적 json.dumps를 사용하며 DjangoJSONEncoder가 디폴트 지정됨.

DRF에서의 JSON 응답

DRF를 통한 HttpResponse JSON 응답

qs = Post.objects.all()
serializer = PostModelSerializer(qs, many=True)
from rest_framework.response import Response
response = Response(serializer.data) # text/html 기본값
# Response에서는 JSON 직렬화가 Lazy하게 동작
# 실제 응답 생성시 .rendered_content 속성에 접근하며 이때 변환 이뤄짐

DRF의 모든 뷰는 APIView를 상속받습니다.
APIView를 통해 Response에 다양한 속성이 지정됩니다.

DRF 에서의 활용예제

from rest_framework import genericsclass PostListAPIView(generics.ListAPIView):
queryset = Post.objects.all()
serializer_class = PostModelSerializer
post_list = PostListAPIView.as_view()

ListAPIView는 리스트 기능만 지원해줍니다! (5가지 다 사용하고 싶을 땐 ViewSet사용을..)

포스팅 조회 응답에서 글쓴이 이름을 조회하고 싶을 때

author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) 필드가 있을 때,

serializers.py 에서 fields = ‘__all__’ 로 사용시

author : 1 

이런식으로 알아보기 쉽지 않게 author의 pk로 뜨게 됩니다.
하지만 serializers.py에서 serializer.ReadOnlyField를 통해 FK의 필드값을 읽어와서

class PostSerializer(serializers.ModelSerializer):
username = serializers.ReadOnlyField(source='author.username')
# fk인 author의 username을 가져와서
class Meta:
model = Post
fields = ['pk', 'username', 'message', 'created_at', 'updated_at']

이런식으로 읽어온 값을 fields에 지정해주면
author : 1 이 아닌 username : ‘홍길동’ 이런 식으로 응답을 받을 수 있겠죠!

# 아니면 이 방법으로도 가능합니다!( 중첩된 Serializer 사용 )
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ['username', 'email']
class PostSerializer(serializers.ModelSerializer):
author = AuthorSerializer()
class Meta:
model = Post
fields = '__all__'

--

--