[Django] Serializer, Serializer, SERIALIZER - 2

SangHun·2021년 7월 4일
0
post-thumbnail

1번 글에 이어서!

Model Serializer

진짜 serializer의 매력은 이 Model Serializer에서 나온다.

이전 글에서 사용된 예시를 살짝 변형해서,
장고 모델을 만들어 보자.

from django.db import models

class Artist(models.Model):
    name = models.CharField(max_length=20)
    number = models.CharField(max_length=20)
    company = models.CharField(max_length=20)
    members = models.IntegerField()
    genre = models.CharField(max_length=20)
    debut_dt = models.DateField()
    dismiss_dt = models.DateField()

GET 요청으로 가수의 정보를 반환해주거나
POST 요청으로 새로운 가수의 정보를 생성 및 저장하는 코드라고 가정하자.

다양한 방법이 있겠지만,
rest framework의 방식대로 해보면 아래와 같이 코드를 작성할 수 있다.

# serializer
class ArtistSerializer(serializers.ModelSerializer):
    class Meta:
        model = Artist
        fields = '__all__'
        
# view
class ArtistListCreate(generics.ListCreateAPIView):
    queryset = Artist.objects.all()
    serializer_class = ArtistSerializer

generic view를 활용하여 작성했다.

이 코드는 아래와 같은 동작을 한다.

GET요청에는 모든 Artist 모델 객체를 반환해준다.
POST요청에는 동봉된 데이터로 새로운 Artist모델 객체를 생성하고 DB에 저장한다.

이렇게 짧은 코드로 검증부터 반환, 저장까지 모두 가능해진다.

물론 이게 다가 아니다!
위는 기본 코드일 뿐이고 추가적인 동작을 하게할 수 있다.

예를 들어, dissmiss_dt 필드는 write only로 설정하고 싶다면?

# serializer
class ArtistSerializer(serializers.ModelSerializer):
    class Meta:
        model = Artist
        fields = '__all__'
        extra_kwargs = {'dissmiss_dt': {'write_only': True}}

혹은 debut_dt 필드를 read only 필드로 설정하고 싶다면??

# serializer
class ArtistSerializer(serializers.ModelSerializer):
    class Meta:
        model = Artist
        fields = '__all__'
        read_only_fields = ['debut_dt']

더 나아가서,
새로운 모델 객체를 생성하고 DB에 저장하는 단계에 추가적인 작업을 끼워넣을 수 있다.

예를 들어, company 필드에 해싱을 적용하여 저장하는 작업을 해보자.

# serializer
class ArtistSerializer(serializers.ModelSerializer):
    class Meta:
        model = Artist
        exclude = ['company']

# view
class ArtistListCreate(generics.ListCreateAPIView):
    queryset = Artist.objects.all()
    serializer_class = ArtistSerializer
    
    def perform_create(self, serializer):
       company = hash_func(self.request.POST.get('company'))
       serializer.save(company=company)

소속사 이름을 왜 해싱하냐고 물으신다면 할 말이 없긴 하지만...
이렇게 할 수도 있다는 걸 보여드리려는 것!

사실 이런 방식은

POST 요청을 보낸 사용자의 정보를 같이 저장
사용자 정보를 저장할 때, 비밀번호를 해싱

등의 작업에 사용된다.

문제점

여기가지 serializer에 대한 설명이다.
꽤나 쓰기 편하고,
조금만 공부해도 금방 자유자재로 써먹을 수 있어보인다.

허나 serializer를 포함하여, rest framework에는 단점이 꽤나 있다.
개인적으로 단점이 매우 많다고 느껴진다...

사견을 곁들여서 문제점을 써보도록 하겠다.

1. 속도

느리다.
이는 rest framework의 근본적인 문제로도 여겨진다.

왜 느릴까?

소스 코드를 한 번 슥 훑어보면 감이 온다.

여기저기서 추상화된 코드가 서로를 호출하고 리턴하고 다시 다른 함수를 호출하고...

소스 코드의 가독성이 좋고 customize하기도 좋지만,
low-level 최적화는 거의 없다.

느린게 대수인가? 어차피 파이썬은 느리다!
라고 할 수 있겠지만,
느려도 너무 느리고!
파이썬에서도 충분히 많은 종류의 최적화가 존재하지만
뭔가 고도화된 최적화가 있지 않는다...

2. 필수적인 소스 코드 리뷰

소스 코드의 가독성이 좋다고는 했지만,
소스 코드를 읽는 노력이 적어도 된다는 뜻은 아니다.
공식 문서에서도 소스 코드를 참조하라는 문구가 자주 등장한다.

예를 들면, save(), create(), perform_create()와의 관계라든가

어떤 attribute가 어디서 어떻게 쓰이고
어떻게 override해야 하는가 등등...

그렇다고 소스 코드의 일부분만 읽어서 되는 것도 아니다.

serializer 부분을 읽다가,
generic view를 읽다가,
mixin을 읽다가 다시 돌아가고...

아주 많은 시간이 소모된다.

Alternatives

먼저 serializer의 대안책부터 알려드리겠다.

Pydantic

Pydantic은 파이썬 타입 어노테이션을 기반으로한 데이터 검증 및 세팅 설정 라이브러리다.

파이썬 타입을 기반으로 하기에,
파이썬만 잘 다뤄왔어도 어느 정도 적응이 수월하다.

문자열 타입에 대한 데이터 검증을 예로 들면,

# serializer
class Name(serializer.Serializer):
    name = serializer.CharField(max_length=10) # or
    name = serializer.TextField()

# pydantic
class Name(pydantic.BaseModel):
    name: str

이처럼 추가적인 API에 대한 정보를 굳이 알지 않아도 어느정도 코드 작성이 가능한 수준이다.

Pydantic을 Django에서 활용한 프레임워크가 Ninja다.

마무리

이전 글을 쓴 뒤 참 오랜 시간이 흘러서
원래 쓰려고 했던 내용을 좀 잊어먹기도 했다...ㅠ
serializer라는 추상적이고도 애매모호한 주제를 다루다보니 범위를 어디까지 정해야 하는 것이고,
얼마나 깊이 다뤄야하는지도 참 난해했다.

이번 글도 서둘러서 끝나는 감이 없잖아 있지만,
차라리 이렇게 빠르게 끝을 내야 계속 글쓰기 편하다.
시리얼라이저... rest framework... 하...

profile
개발괴발자

0개의 댓글