Ssul's Blog

Django Serializer 이해하기(직렬화, 역직렬화) 본문

dev/까먹지마

Django Serializer 이해하기(직렬화, 역직렬화)

Ssul 2024. 8. 16. 17:22

1. 내가 이해하는 직렬화, 역직렬화 구분

- A: 사람이 읽기는 어렵지만, 기계에게 효과적인 데이터(예: 0xB0, 0xA0)

- B: 사람이 읽기는 편하지만, 기계에게는 비효율적인 데이터(예: {"id": 1, "contents": '첫번째 글'})

 

직렬화: B -> A (dict -> bytes): 조금더 배우고나서 적음 > dict > byte

역직렬화: A -> B(bytes -> dict): 조금 더 배우고나서 적음: byte > dict > 객체

 

2. Django에서 직렬화 이해(GET과정)

DB에서 인스턴스 가져오기
ins0 = Comment.objects.all()[0]
serializer에 넣어서 dict객체로
sr = CommentSerializer(instance=ins0) #instance에 넣어준다
sr.data #dict형태
dict객체를 직렬화해서 bytes로 클라이언트에게 전달
JSONRenderer().render(sr.data)
#또는
Response(sr.data)

 

3. Django에서 역직렬화 이해(POST, UPDATE과정)

클라이언트에서 받은 요청(bytes)을 dict로 변환(viewsets또는 views.py에 있음)
tmpdata = JSONParser().parse(BytesIO(클라이언트요청))
#또는 보통 밑에 request 해결됨
tmpdata = request.data #request가 byte형태의 데이터를 > dict형태로
serializer에 넣어서 instance 생성 준비
dsr = CommentSerializer(data=tmpdata) #(중요)data에 넣는다, instance,data둘다 이용시 update
#해당 과정을 조금 더 디테일하게 들어가면, 댓글을 다는 과정에서
#CommentsModelViewSet.create() > get_serializer(data=request.data) 여기까지 진행

 

유효성 검사를 해서, 성공하면 validated_data생성
dsr.is_valid()
#통과하면 dsr.is_valid()는 True, dsr.errors는 {}
#그리고 dsr.validated_data에 통과된 최종 데이터들이 dict형태로 담김
인스턴스 생성(*인스턴스는 validated_data로 만든다)
instance = Comment(**dsr.validated_data)
instance.save()
#해당 과정을 조금 더 디테일하게 들어가면, 댓글을 다는 과정에서
#views.perform_create(serializer) -> serializer.save() -> serializer.create

 

4. APIView문서보면서 완벽히 이해하기(READ(GET):RetrieveAPIView, WRITE(POST):CreateAPIView)

READ(GET):RetrieveAPIView
def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)
        
#우리가 배운것처럼 DB에서 인스턴스 가져와서,
#시리얼라이저에 넣어서 dict
#그 dict를 Response로 bytes로 변환하여 전달 = JSONRenderer().render(~~~)
WRITE(POST):CreateAPIView
def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
        
#클라이언트에서 받은 데이터 request.data를 시리얼라이저에 넣기
#is_valid로 유효성 검사
#perform_create *여기서 instance만들고, db저장
def perform_create(self, serializer):
        serializer.save()
ModelSerializer
    def save(self, **kwargs):
        assert hasattr(self, '_errors'), (
            'You must call `.is_valid()` before calling `.save()`.'
        )

        assert not self.errors, (
            'You cannot call `.save()` on a serializer with invalid data.'
        )

        # Guard against incorrect use of `serializer.save(commit=False)`
        assert 'commit' not in kwargs, (
            "'commit' is not a valid keyword argument to the 'save()' method. "
            "If you need to access data before committing to the database then "
            "inspect 'serializer.validated_data' instead. "
            "You can also pass additional keyword arguments to 'save()' if you "
            "need to set extra attributes on the saved model instance. "
            "For example: 'serializer.save(owner=request.user)'.'"
        )

        assert not hasattr(self, '_data'), (
            "You cannot call `.save()` after accessing `serializer.data`."
            "If you need to access data before committing to the database then "
            "inspect 'serializer.validated_data' instead. "
        )

        validated_data = {**self.validated_data, **kwargs}

        if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            assert self.instance is not None, (
                '`update()` did not return an object instance.'
            )
        else:
            self.instance = self.create(validated_data)
            assert self.instance is not None, (
                '`create()` did not return an object instance.'
            )

        return self.instance
        
        #self.instance가 있으면 update호출, 없으면 create호출
        #그리고 호출사 validated_data 입력
#해당 내용은 Comment.objects.create(**validated_data)와 동일한 역할수행

def create(self, validated_data):
        raise_errors_on_nested_writes('create', self, validated_data)

        ModelClass = self.Meta.model

        try:
            instance = ModelClass._default_manager.create(**validated_data)
        except TypeError:
            tb = traceback.format_exc()
            msg = (
                'Got a `TypeError` when calling `%s.%s.create()`. '
                'This may be because you have a writable field on the '
                'serializer class that is not a valid argument to '
                '`%s.%s.create()`. You may need to make the field '
                'read-only, or override the %s.create() method to handle '
                'this correctly.\nOriginal exception was:\n %s' %
                (
                    ModelClass.__name__,
                    ModelClass._default_manager.name,
                    ModelClass.__name__,
                    ModelClass._default_manager.name,
                    self.__class__.__name__,
                    tb
                )
            )
            raise TypeError(msg)

        # Save many-to-many relationships after the instance is created.
        if many_to_many:
            for field_name, value in many_to_many.items():
                field = getattr(instance, field_name)
                field.set(value)

        return instance