이전 글에서 REST framework의 아주 간단한 예시를 다뤘다. 다만, serializer 클래스와 관련하여 이해가 안 되는 부분이 있어서 알아볼 예정이다. 아래의 내용은 Django REST framework의 공식문서를 번역하여 정리했다.
serializers
Serializers는 querysets과 model 인스턴스와 같은 복잡한 데이터를 JSON 과 XML 등 기본적인 콘텐츠 타입으로 렌더링 할 수 있는 파이썬 네이티브 데이터타입으로 변환시켜 준다. Serializers는 유효한 데이터가 입력되기만 하면 다시 복잡한 데이터로 돌아갈 수 있는 deserialization(역직렬화)도 제공한다.
REST framework의 serializer는 Django의 Form 과 ModelForm 클래스와 매우 비슷하다. 또한, serializers를 더 간편하게 만들 수 있는 ModelSerializer클래스도 제공한다.
Serializers 선언하기
예로 간단한 클래스를 object를 만들어보자.
from datetime import datetime
class Comment:
def __init__(self, email, content, created=None):
self.email = email
self.content = content
self.created = created or datetime.now()
comment = Comment(email='leila@example.com', content='foo bar')
이제 Comment 클래스의 형식에 맞는 데이터를 serialize, deserialize 할 수 있는 serializer를 선언 할것이다.
Django의 Form과 같이 보이는 serializer를 선언하자.
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
오브젝트 serialize 하기
이제 comment, comment 리스트를 serialize하기 위해 CommentSerializer 를 사용할 수 있다. 이제 만든 Serializer 클래스를 사용해 보자.
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
이 경우에는 파이썬 네이티브 데이터타입으로 변환했는데 serialization을 하여 json 타입으로 렌더를 해보자.
from rest_framework.renderers import JSONRenderer
json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
오브젝트 deserialize 하기
desrialize 하는 것도 비슷한데 먼저 json파일을 파이썬 네이티브 데이터타입으로 분석하고 저장해야 한다.
import io
from rest_framework.parsers import JSONParser
stream = io.BytesIO(json)
#json 파일 읽기
data = JSONParser().parse(stream)
#json 타입을 파이썬 네이티브 데이터타입으로 변환하여 저장
이제 네이티브 데이터 타입이 저장된 data를 파이썬의 딕셔너리로 복원할 수 있다.
serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
인스턴스 저장하기
유효한 데이터를 기반으로 오브젝트 인스턴스를 만들거나 수정하고 싶다면 .create() 와 .update() 메소드를 구현할 필요가 있다.
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
def create(self, validated_data):
return Comment(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
return instance
오브젝트 인스턴스가 Django models에 해당하는 경우 이 메서드들이 오브젝트를 데이터베이스에 저장하게 하고 싶을 것이다. Comment 가 Django model일 시, 메서드를 다음과 같이 만들어야 한다.
def create(self, validated_data):
return Comment.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance
이제 데이터를 deserialize 할 때 .save() 를 호출하여 오브젝트 인스턴스를 반환할 수 있다.
comment = serializer.save()
.save() 는 인스턴스화한 Serializer 클래스에 따라서 새로운 인스턴스를 만들거나, 이미 존재하는 인스턴스를 업데이트할 것이다.
# .save() 하면 새로운 인스턴스가 만들어진다.
serializer = CommentSerializer(data=data)
# .save() 하면 `comment`가 업데이트된다.
serializer = CommentSerializer(comment, data=data)
.create() 와 .update() 메소드는 옵션이므로 사용하는 케이스에 따라서 다 만들어도, 하나도 안 만들어도 상관없다.
.save() 메서드로 추가적인 속성 전달하기
인스턴스를 저장하는 시점 현재 유저, 현재 시간 등 클라이언트에서 요청할 때에는 없는 부분들을 담고 있는 추가적인 데이터를 새로운 데이터로 추가하고 싶을 수도 있다.
이를 해결하기 위해서는 추가적인 매개변수들을 .save()를 호출할 때 포함하여 할 수 있다. 예를 들면,
serializer.save(owner=request.user)
모든 추가한 매개변수들은 validated_data의 속성으로 불러올 수 있다.
.save() 직접 오버라이드 하기
몇몇 케이스에서는 .create() 와 .update() 메소드가 별로 필요가 없을 때가 있다. 예를 들면 새로운 인스턴스를 만드는 것이 아니라 이메일이나 메시지들을 전송하는 인스턴스가 있을 수 있다.
이러한 케이스에서는 더 쉽고 의미가 있도록 save()를 오버라이드 할 수 있다.
class ContactForm(serializers.Serializer):
email = serializers.EmailField()
message = serializers.CharField()
def save(self):
email = self.validated_data['email']
message = self.validated_data['message']
send_email(from=email, message=message)
참고로 위의 케이스는 serializer의 .validated_data의 프로퍼티로 접근할 수 있는 방법이다.
참고자료
https://www.django-rest-framework.org/api-guide/serializers/#serializers
'웹 > Django' 카테고리의 다른 글
[REST framework] 튜토리얼 (0) | 2024.04.13 |
---|