빠른 API 개발: DRF는 Django의 강력한 기능과 결합하여 빠르고 효율적인 API 개발을 지원한다. 일반적인 API 개발 작업을 위한 많은 기능과 유틸리티를 제공하며, 반복적인 작업을 최소화하여 개발 시간을 단축시킨다.
유연한 시리얼라이저: DRF는 시리얼라이저를 통해 데이터 직렬화와 역직렬화를 지원한다. 시리얼라이저를 사용하면 데이터 모델과 JSON 또는 다른 형식의 데이터 간의 변환 작업을 간편하게 처리할 수 있다.
인증과 권한 관리: DRF는 다양한 인증 방법과 권한 관리 기능을 제공하여 API 엔드포인트의 보안을 강화할 수 있다. 사용자 인증, 토큰 기반 인증, OAuth 및 JWT(Jason Web Token) 인증 등 다양한 인증 방식을 지원한다.
API 문서화: DRF는 API 문서화를 지원하는 기능을 제공한다. API의 엔드포인트, 요청 및 응답 형식, 인증 방법 등에 대한 자동화된 문서를 생성할 수 있으며, 개발자와 클라이언트 간의 소통과 협업을 용이하게 한다.
재사용 가능한 컴포넌트: DRF는 재사용 가능한 컴포넌트를 제공하여 코드의 재사용성을 높인다. 뷰(Views), 시리얼라이저, 믹스인(Mixins) 등 다양한 컴포넌트를 사용하여 일반적인 작업을 쉽게 구현하고 코드의 일관성을 유지할 수 있다.
테스트 지원: DRF는 테스트를 작성하고 실행하기 위한 도구와 기능을 제공한다. API 테스트를 자동화하고 유닛 테스트 및 통합 테스트를 쉽게 작성하여 애플리케이션의 품질과 안정성을 향상시킬 수 있다.
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
[
{
"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": "테스트"
}
}
]
[
{
"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
}
]
역직렬화는 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)
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로 응답해준다.
만약 응답 결과를 커스텀하고 싶은 경우에는 사용하지 않으면 된다.