[drf] drf를 쓰는 이유, serializer

최동혁·2023년 5월 14일
0

DRF

목록 보기
18/19

DRF를 쓰는 이유

  • DRF(Django REST Framework)는 Django 기반의 웹 애플리케이션에서 RESTful API를 쉽게 개발하고 관리하기 위해 사용되는 오픈 소스 프레임워크이다.
  • DRF를 사용하는 이유는 다음과 같다.
  1. 빠른 API 개발: DRF는 Django의 강력한 기능과 결합하여 빠르고 효율적인 API 개발을 지원한다. 일반적인 API 개발 작업을 위한 많은 기능과 유틸리티를 제공하며, 반복적인 작업을 최소화하여 개발 시간을 단축시킨다.

  2. 유연한 시리얼라이저: DRF는 시리얼라이저를 통해 데이터 직렬화와 역직렬화를 지원한다. 시리얼라이저를 사용하면 데이터 모델과 JSON 또는 다른 형식의 데이터 간의 변환 작업을 간편하게 처리할 수 있다.

  3. 인증과 권한 관리: DRF는 다양한 인증 방법과 권한 관리 기능을 제공하여 API 엔드포인트의 보안을 강화할 수 있다. 사용자 인증, 토큰 기반 인증, OAuth 및 JWT(Jason Web Token) 인증 등 다양한 인증 방식을 지원한다.

  4. API 문서화: DRF는 API 문서화를 지원하는 기능을 제공한다. API의 엔드포인트, 요청 및 응답 형식, 인증 방법 등에 대한 자동화된 문서를 생성할 수 있으며, 개발자와 클라이언트 간의 소통과 협업을 용이하게 한다.

  5. 재사용 가능한 컴포넌트: DRF는 재사용 가능한 컴포넌트를 제공하여 코드의 재사용성을 높인다. 뷰(Views), 시리얼라이저, 믹스인(Mixins) 등 다양한 컴포넌트를 사용하여 일반적인 작업을 쉽게 구현하고 코드의 일관성을 유지할 수 있다.

  6. 테스트 지원: DRF는 테스트를 작성하고 실행하기 위한 도구와 기능을 제공한다. API 테스트를 자동화하고 유닛 테스트 및 통합 테스트를 쉽게 작성하여 애플리케이션의 품질과 안정성을 향상시킬 수 있다.

serializer

  • Django REST Framework(DRF)에서 Serializer는 데이터의 복잡한 유형을 Python의 데이터 유형으로 변환하거나, Python 데이터 유형을 다시 복잡한 유형으로 변환하는 역할을 한다.
  • 이러한 과정은 '직렬화(Serialization)'와 '역직렬화(Deserialization)'라고 불린다.

직렬화(Serialization)

  • 직렬화는 복잡한 데이터 유형(예: Django 모델 인스턴스나 쿼리셋)을 Python의 기본 데이터 유형(예: dict, list, str, int, float, bool 등)으로 변환하는 과정을 말합니다. 이는 주로 클라이언트에게 데이터를 JSON, XML 등의 형태로 전달할 때 사용됩니다. Serializer의 to_representation 메서드가 이 역할을 수행합니다.

to_representation

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'

    def to_representation(self, instance):
        response = super().to_representation(instance)
        response["category"] = CategorySerializer(instance.category).data
        return response
  • to_representation을 통해 인스턴스나 쿼리셋을 python의 기본 데이터 유형으로 변환해준다.
  • Product는 category 모델을 참조하고 있기 때문에, 직렬화를 수행했을때 category의 객체가 오는 것이 아닌, 참조하고 있는 category_id만 오게 된다.
  • 객체를 전부 직렬화 해주기 위해 추가 작업을 하는 과정이다.
  • super().to_representation(instance)를 통해 해당 인스턴스를 직렬화 한 후, 직렬화의 대한 결과인 response의 category key에 category 객체로 업데이트를 해주는 것이다.
[
        {
            "id": 7,
            "price": 1000,
            "cost": 800,
            "name": "바나나나",
            "name_initial": "ㅂㄴㄴㄴ",
            "description": "상품 설명",
            "barcode": "상품 바코드11",
            "expiration_date": "2023-05-31",
            "size": "s",
            "created_at": "2023-05-14T06:10:56.219473Z",
            "updated_at": "2023-05-14T06:11:31.767502Z",
            "user": 3,
            "category": {
                "id": 1,
                "name": "테스트"
            }
        }
    ]
  • 그렇다면 response는 위 처럼 나오게 되는데, 만약 category key를 업데이트 하지 않았다면?
[
        {
            "id": 7,
            "price": 1000,
            "cost": 800,
            "name": "바나나나",
            "name_initial": "ㅂㄴㄴㄴ",
            "description": "상품 설명",
            "barcode": "상품 바코드11",
            "expiration_date": "2023-05-31",
            "size": "s",
            "created_at": "2023-05-14T06:10:56.219473Z",
            "updated_at": "2023-05-14T06:11:31.767502Z",
            "user": 3,
            "category": 1
        }
    ]
  • 이런식으로 카테고리의 객체가 아닌 category_id만 담겨서 직렬화 된다.

역직렬화(Deserialization)

  • 역직렬화는 Python의 기본 데이터 유형을 복잡한 데이터 유형으로 변환하는 과정을 말하며, 주로 클라이언트로부터 받은 JSON 데이터 등을 Django 모델 인스턴스로 변환할 때 사용된다.

  • Serializer의 to_internal_value 메서드가 이 역할을 수행한다.

  • 보통 client로 부터 받은 데이터는 JSON 형식이다.

  • 이러한 형식의 데이터를 역직렬화 하는 코드는 아래와 같다.

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all().select_related('user', 'category')
    serializer_class = ProductSerializer
    permission_classes = [IsAuthenticated]
    pagination_class = ProductPagination

    def create(self, request, *args, **kwargs):
        request.data["user"] = request.user.pk
        category, _ = Category.objects.get_or_create(
            name=request.data["category"]
        )
        request.data["category"] = category.pk
        serializer = self.get_serializer(data=request.data)
        global result

        try:
            serializer.is_valid()
            serializer.save()
            result["meta"]["code"] = status.HTTP_201_CREATED
            result["meta"]["message"] = "ok"
            result["data"] = serializer.data

        except:
            if "barcode" in serializer.errors:
                result["meta"]["code"] = status.HTTP_409_CONFLICT
                result["meta"]["message"] = serializer.errors
                result["data"] = "null"
                return Response(result, status=status.HTTP_409_CONFLICT)

            else:
                result["meta"]["code"] = status.HTTP_400_BAD_REQUEST
                result["meta"]["message"] = serializer.errors
                result["data"] = "null"
                return Response(result, status=status.HTTP_400_BAD_REQUEST)

        return Response(result, status=status.HTTP_201_CREATED)
  • get_serializer를 통해 위에서 선언한 serializer_class인 ProductSerializer에 client로 부터 요청 받은 데이터를 역직렬화하게 된다.
  • 역직렬화한 결과를 serializer 변수에 담아준다. 아래는 역직렬화한 결과이다.
ProductSerializer(context={'request': <rest_framework.request.Request: POST '/products/'>, 'format': None, 'view': <product.views.ProductViewSet object>}, data={'c
ategory': 1, 'price': 1000, 'cost': 800, 'name': '바나나나', 'description': '상품 설명', 'barcode': '상품 바코드15', 'expiration_date': '2023-05-31', 'size': 's', 'user': 3}):
    id = IntegerField(label='ID', read_only=True)
    price = IntegerField(max_value=2147483647, min_value=-2147483648)
    cost = IntegerField(max_value=2147483647, min_value=-2147483648)
    name = CharField(max_length=30)
    name_initial = CharField(allow_blank=True, max_length=30, required=False)
    description = CharField(allow_blank=True, required=False, style={'base_template': 'textarea.html'})
    barcode = CharField(max_length=30, validators=[<UniqueValidator(queryset=Product.objects.all())>])
    expiration_date = DateField()
    size = ChoiceField(choices=(('s', 'small'), ('l', 'large')), required=False)
    created_at = DateTimeField(read_only=True)
    updated_at = DateTimeField(read_only=True)
    user = PrimaryKeyRelatedField(queryset=User.objects.all())
    category = PrimaryKeyRelatedField(queryset=Category.objects.all())
  • 위의 결과에서 볼 수 있듯이, 요청 받은 JSON 데이터를 장고 모델 인스턴스 형식으로 변환해준것을 확인할 수 있다.

  • 그 후, 유효성 검사인 is_valid()를 거치고 난 후, serializer.data에 접근을 하면 직렬화한 결과에 대해 볼 수 있다.

주의

  • 만약 역직렬화 하는 과정에서 파라미터로 data를 주게 되면, 유효성 검사인 is_valid()를 하지 않는 한 직렬화한 결과의 data를 뽑아낼 수 없다.

  • 역직렬화 하는 과정에서 파라미터에 data를 주는 경우는 데이터를 생성하거나, 수정하는 경우만 해당이 되기 때문에 그러한 경우 무조건 유효성 검사를 하라는 로직이 내부 구현되어 있는 것이다.

  • 그래서 만약 생성 혹은 수정을 하는 것이 아니라면 파라미터에 data를 넣지말고 검색이나 삭제할 인스턴스를 파라미터로 집어넣어서 굳이 유효성 검사를 거치지 않고 직렬화한 결과를 뽑아내주자.

  • 또한, is_valid()에서 파라미터에 raise_exception=True를 주게 된다면 유효성 검사를 통과하지 않았을 때에 자동으로 400 status code를 가진 결과를 Response로 응답해준다.

  • 만약 응답 결과를 커스텀하고 싶은 경우에는 사용하지 않으면 된다.

profile
항상 성장하는 개발자 최동혁입니다.

0개의 댓글