[Django Rest Framework] 직렬화(Serializer)에 대해서 알아보자
직렬화
모든 프로그래밍 언어의 통신에서 데이터는 필히 문자열로 표현되야 합니다.
송신자 : 객체를 문자열로 변환하여 전송 -> 직렬화
수신자 : 수신한 문자열을 다시 객체로 변환하여, 활용 -> 비직렬화
각 언어에서 모두 지원하는 직렬화 포맷(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 타입의 응답을 해야만 함.
- 직접 json.dumps를 통해 문자열을 획득, HttpResponse를 통해 응답
- 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 = PostModelSerializerpost_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__'