웹/Django

[REST framework] Serializers 1

implement 2024. 4. 14. 12:00
728x90

이전 글에서 REST framework의 아주 간단한 예시를 다뤘다. 다만, serializer 클래스와 관련하여 이해가 안 되는 부분이 있어서 알아볼 예정이다. 아래의 내용은 Django REST framework의 공식문서를 번역하여 정리했다.

 

serializers

Serializers는  querysets과 model 인스턴스와 같은 복잡한 데이터를  JSON 과  XML 등 기본적인 콘텐츠 타입으로 렌더링 할 수 있는 파이썬 네이티브 데이터타입으로 변환시켜 준다. Serializers는 유효한 데이터가 입력되기만 하면 다시 복잡한 데이터로 돌아갈 수 있는  deserialization(역직렬화)도 제공한다.

 

REST frameworkserializer는 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

반응형