[django] DRF - serializer

EMMA·2022년 4월 30일
0
post-custom-banner

🖥 기업 프로젝트 DAY - 5, 어느덧 1주일이 훌쩍 갔다.

기본 회원가입 API를 작업하면서 조금씩 맛보고 있는 DRF - serializer 기능과 APIview에 대해 기초 정리.


serializer, 누구냐 넌...

클라이언트-서버가 데이터를 주고받음에 있어서 문제가 없도록 serialize & deserialize 해주는 기능이다.

모델링을 create/update 할 때, python 데이터타입으로 변환하여 그대로 메모리에 저장하는 것이다.

결국, 데이터 구조나 객체를 다른 컴퓨터 환경에서도 저장하고 재구성할 수 있도록 포맷을 변환하는 작업이라고 할 수 있다.

django에서는 Form이 유사한 역할을 하지만, 결정적으로 아래의 차이가 있다.

  • django Form : html tag를 생성
  • DRF serializer : JSON을 생성

Serializing

공식문서의 예시를 보자.

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')

이를 serializing 하면 아래와 같다.

from rest_framework import serializers

class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

이제 맨 처음에 선언한 commentCommentSerializer에 담아보자.

serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

Deserializing/Validation

예시 코드는 아래와 같다.

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)}
  • Deserializing 할 때는, data에 데이터를 넣어 전달한다.
  • 바로 저장하는 것이 아니라, is_valid()를 통해 유효성 검사를 진행
  • 검사를 통과한 데이터는 validated_data에 담긴다.

실제 코드 (회원가입)

#serializer.py 

from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from .models import User

class UserSerializer(serializers.Serializer):
    email      = serializers.EmailField(validators = [UniqueValidator(queryset = User.objects.all())])
    last_name  = serializers.CharField(max_length = 50, write_only = True) 
    first_name = serializers.CharField(max_length = 50, write_only = True)
    password   = serializers.CharField(max_length= 128, write_only = True) 
    
    def create(self, validated_data):
        return User.objects.create_user(**validated_data)
  • email: UniqueValidator를 사용해서, 기존 DB에 있는 email인지 아닌지 확인할 수 있다
  • last_name/first_name: 50 characters를 넘으면 안되며, write_only 속성을 통해 response 시(serializing할 때) 나타나지 않도록 했다.
  • password: 위와 동일

serializer를 기반으로, view는 아래와 같이 작성되었다.

#views.py

from rest_framework.permissions import AllowAny
from rest_framework.generics import CreateAPIView

from .serializers import UserSerializer

class SignUpView(CreateAPIView):
    permission_classes = [AllowAny]
    serializer_class   = UserSerializer
  • CreateAPIView는 post만 처리하는 handler
  • permission_classes를 통해 회원가입은 모두가 접근할 수 있도록 했다
  • UserSerializerseriazlier_class에 담아 실행시키면, 검증과정 후에 post까지 실행되어 DB에 저장된다.

CreateAPIView의 code를 보면, 아래와 같이 정의되어 있어 가능한 것. (is_valid, perfrom_create() 등이 모두 설정되어 있다)

사수께서 CreateAPIView를 사용했기 때문에 post 함수도 작성할 필요 없어요~ 라고 했을 때 동공지진 일으키며 지웠는데 정말 작동했고 너무 신세계였다...


#CreateAPIView

class CreateAPIView(mixins.CreateModelMixin,GenericAPIView):
    """
    Concrete view for creating a model instance.
    """
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

#def create()

class CreateModelMixin(object):
    """
    Create a model instance.
    """
    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)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}


참고 자료
https://github.com/encode/django-rest-framework/blob/b1c4d8b59b67084ed07a35ea9a35629805039aaa/rest_framework/mixins.py#L18

profile
예비 개발자의 기술 블로그 | explore, explore and explore
post-custom-banner

0개의 댓글