DRF에서 Blob 데이터 처리

강태원·2024년 4월 24일
0

프로젝트를 진행하던 도중, 데이터베이스의 blob 필드를 사용해야 할 일이 생겼습니다.

처음에는 클라이언트가 작성한 글을 저장하려고 할 때 장고에서 CharField로 생성한 필드에 저장하려고 했으나, CharField는 max_length를 반드시 명시해줘야 하기 때문에 글이 한도 길이를 지정하고 싶지 않았고, 글의 길이가 짧을 경우 패딩 문자가 저장되는 용량이 아까웠습니다.

그래서 어떻게 할 것인가?

클라이언트 측에서 보내준 글 내용을 Binary 값으로 바꾸어 데이터베이스의 Blob 필드에 저장하고자 합니다!

다르게 생각해본 방법은 파일로 만들어서 보관해볼까도 싶었지만, 서비스의 특성 상 읽어오는 작업이 많고 작성할 때의 작업이 너무 오래걸릴 것 같아 폐기했습니다.

간단할 줄 알았는데..

장고에서 모델을 설정할 때 CharField로 지정한 부분을 BinaryField로 바꾸고 저장하면 바로 끝나겠다 싶었습니다.

# Model 필드 BinaryField로 수정
explain = models.BinaryField()

수정한 뒤에 Postman으로 데이터를 보내 테스트를 해봤으나,
serialzier의 is_valid()에서 계속 False가 떴습니다.

따로 알아본 결과 DRF의 Serializer에서는 BinaryField를 지원해주지 않는다! 라는 사실을 알게되었고, 어떻게 할까 생각하던 중 커스텀필드를 작성하자는 생각을 하게 되었습니다.

    def to_internal_value(self, data):
        """
        Transform the *incoming* primitive data into a native value.
        """
        raise NotImplementedError(
            '{cls}.to_internal_value() must be implemented for field '
            '{field_name}. If you do not need to support write operations '
            'you probably want to subclass `ReadOnlyField` instead.'.format(
                cls=self.__class__.__name__,
                field_name=self.field_name,
            )
        )

    def to_representation(self, value):
        """
        Transform the *outgoing* native value into primitive data.
        """
        raise NotImplementedError(
            '{cls}.to_representation() must be implemented for field {field_name}.'.format(
                cls=self.__class__.__name__,
                field_name=self.field_name,
            )
        )

위 내용은 rest_framwork.fields의 Field 클래스 내부 함수입니다.
반드시 두 함수는 오버라이딩 되어 재정의 되어야 필드로 쓸 수 있죠!

fields.py에서 미리 정의되어 있는 다른 필드들을 봐도 모두 오버라이딩 되어있습니다!

해결방법

to_internal_value 함수는 외부에서 데이터베이스로, to_representation 함수는 데이터베이스에서 외부로 값을 보낼 때 호출되는 함수들입니다.

우리는 클라이언트에게서 str값을 받아 binary형태로 바꾸어 저장할 것이므로
to_internal_value 함수에서는 encode, to_representation 함수에서는 decode를 해주면 되겠죠?

# 제가 새로 생성한 바이너리 필드입니다!
class MyBinaryField(serializers.Field):
    def to_representation(self, value):
        return value.decode("utf-8")

    def to_internal_value(self, data):
        return data.encode("utf-8")

이제 시리얼라이저에서 이 필드로 정의해주면 str값을 blob형태로 데이터베이스에 저장하고 blob 값을 str형태로 받아올 수 있습니다.

class TeamCreateSerializer(serializers.ModelSerializer):
    leader_id = serializers.IntegerField()
    explain = MyBinaryField()

    class Meta:
        model = Team
        fields = ["id", "leader_id", "name", "explain", "genre", "like", "version", "image"]

해결완료!

profile
가치를 창출하는 개발자! 가 목표입니다

0개의 댓글