brunch

매거진 백엔드

You can make anything
by writing

C.S.Lewis

by 내가 사는 세상 Nov 26. 2023

Django DRF - Serializer

데이터 가공기계

 고객과 서버 사이에선 수많은 데이터 전송이 벌어진다. 이때 보내주고 받을 데이터를 가공, 정제하는 작업을 Serializer라는 것이 하게 된다. 그래서 serializers.py의 주된 기능은 다음 2가지 이다.


1. 직렬화(serialize) / 역직렬화(deserialize)

2. 검증(validation) 기능





고객한테 보내줄 데이터를 선별한 뒤, json으로 형태를 바꿔주는 것을 직렬화한다고 한다.

반대로 고객이 보내준 데이터를 파이썬 객체로 DB에 저장하는 것을 역직렬화라고 한다.

직렬화 : INSTANCE  -- serializer--→ DICT(사전) → BYTES STRING(JSON형태)

: serializer.data => dict형태                    


역직렬화 : BYTES STRING(JSON형태)   --- bytesio --→   DICT(사전)   --- serializer --→  INSTANCE

                                                                                       b= Serializer(data=data)

                                                                                       b.is_valid()

                                                                                       b.validated_data

                                                                                       binstance = AModel(**a.validated_data)

                                                                                       binstance.save()




나만의 serializer.py를 만들 때 자주 사용하는 함수들


def create(self, validated_data)

: views.py에서 perform_create() -> serializer.save()에서 시작된 것

: ModelSerializer에서 

instance = ModelClass._derault_manager.create(**validated_data)

를 통해 파이썬 객체(모델 인스터스)를 만들어서 DB에 저장하는 것

https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py#L178



def update(self, instance, validated_data)

: views.py에서 perform_create() -> serializer.save()에서 시작된 것

https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py#L175



def validate(self, attrs):

: serializer 필드라는 재료들을 통해 무언가 검증작업이 필요하다면 사용

: ex) password = password2 검증,

: serializer.validated_data를 하면 return 값이 def validate(self, attrs)의 리턴값이다



def save(self, **kwargs):




이를 사용한 예시를 보자.

  # serializers.py

from rest_framework import serializers

from .models import Book


class BookSerializer(serializers.ModelSerializer):

    class Meta:

        model = Book

        fields = ['id', 'title', 'author', 'publication_date']


    def create(self, validated_data):

        return Book.objects.create(**validated_data)


    def update(self, instance, validated_data):

        instance.title = validated_data.get('title', instance.title)

        instance.author = validated_data.get('author', instance.author)

        instance.publication_date = validated_data.get('publication_date', instance.publication_date)

        instance.save()

        return instance


    def validate_title(self, value):

        if not value:

            raise serializers.ValidationError("Title cannot be empty.")

        return value


    def validate_publication_date(self, value):

        from datetime import date

        if value > date.today():

            raise serializers.ValidationError("Publication date cannot be in the future.")

        return value


    def save(self, **kwargs):

        return super().save(**kwargs)



모델에 직접적으로 정의되지 않은 데이터도 보내주고 싶을 때 


class LoginSerializer(serializers.Serializer):
     email = serializers.EmailField(min_length=3, max_length=255)
     password = serializers.CharField(min_length=3, max_length=68, write_only=True)
     username = serializers.CharField(min_length=1, max_length=255, read_only=True)
     tokens = serializers.SerializerMethodField()
     
     def get_tokens(self, obj):
         user = User.objects.get(email=obj['email'])
         return {
             'refresh': user.tokens()['refresh'],
             'access': user.tokens()['access']
         }

 
     class Meta:
         model = User
         fields = ['email', 'password', 'username', 'tokens']

 

email, password, username, tokens처럼 정의하면 #이 4가지를 가공기에 넣어서 변환시킨 뒤, 고객에게 보내줄 의도이다


tokens = serializers.SerializerMethodField()

여기선 def get_tokens(self, obj): 이게 필요하다

 



Tips


- class Meta:

        fields = ['어쩌구']

에 정의된 값들은 또다시 필드로 정의해줄 필요가 없다.




Foreign key로 연결된 것을 id가 아닌 다른 값으로 불러들이고 싶을 때


class ProductListSerializer(ModelSerializer):
    # Category 모델의 pk 아닌 name 추출 - Foreign
    category = serializers.CharField(source='category.name')





Nested Serializer


from rest_framework import serializers

from .models import Post, Comment


class CommentSerializer(serializers.ModelSerializer):

    class Meta:

        model = Comment

        fields = ['id', 'author', 'text']


class PostSerializer(serializers.ModelSerializer):

    comments = CommentSerializer(many=True, read_only=True)

    class Meta:

        model = Post

        fields = ['id', 'title', 'content', 'comments']




 참고자료


공식문서 : https://www.django-rest-framework.org/api-guide/serializers/

김석훈 : Django REST Framework 핵심사항

권태형 : 백엔드를 위한 Django REST Framework with 파이썬 

keyword
매거진의 이전글 Django - static, media
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari