Django REST Framework에서 동일한 ModelViewSet에서 서로 다른 Serializer 사용하기
다음은 동일한 ModelViewSet에서 서로 다른 Serializer를 사용하는 두 가지 방법을 설명합니다.
get_serializer_class 메서드 사용하기:
get_serializer_class
메서드를 오버라이드하여 요청 유형이나 요청 데이터에 따라 사용할 Serializer 클래스를 동적으로 선택할 수 있습니다. 예를 들어, 목록 보기 요청에는 ListSerializer
를 사용하고, 상세 보기 요청에는 DetailSerializer
를 사용할 수 있습니다.
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
def get_serializer_class(self):
if self.request.method == 'GET':
if self.action == 'list':
return ProductListSerializer
else:
return ProductDetailSerializer
return super().get_serializer_class()
lookup_field 및 serializer_class 매개 변수 사용하기:
lookup_field
및 serializer_class
매개 변수를 사용하여 URL 패턴에 기반하여 사용할 Serializer 클래스를 지정할 수 있습니다. 이 방법은 URL에 따라 서로 다른 표현을 제공해야 하는 경우에 유용합니다.
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('products', ProductViewSet, lookup_field='slug')
router.register('products-detail', ProductDetailViewSet, lookup_field='slug')
urlpatterns = [
path('', include(router.urls)),
]
위 코드는 /products/{slug}
경로에 대한 요청에는 ProductViewSet
을 사용하고, /products-detail/{slug}
경로에 대한 요청에는 ProductDetailViewSet
을 사용하도록 라우터를 구성합니다. 각 ViewSet 클래스는 serializer_class
매개 변수를 사용하여 사용할 Serializer 클래스를 지정합니다.
참고:
get_serializer_class
메서드를 사용하는 경우 요청 유형이나 요청 데이터에 따라 동적으로 Serializer 클래스를 선택하는 데 더 유연합니다.lookup_field
및serializer_class
매개 변수를 사용하는 경우 URL 패턴에 따라 사용할 Serializer 클래스를 명확하게 지정할 수 있습니다.
어떤 방법을 사용할지는 구체적인 상황에 따라 다릅니다.
Django REST Framework에서 동일한 ModelViewSet에서 서로 다른 Serializer 사용하기: 예제 코드
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ProductListSerializer(ProductSerializer):
class Meta:
fields = ('id', 'name', 'price')
class ProductDetailSerializer(ProductSerializer):
class Meta:
fields = ('id', 'name', 'price', 'description')
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
def get_serializer_class(self):
if self.request.method == 'GET':
if self.action == 'list':
return ProductListSerializer
else:
return ProductDetailSerializer
return super().get_serializer_class()
이 예제에서는 ProductSerializer
를 기본 Serializer 클래스로 정의합니다. ProductListSerializer
는 id
, name
, price
필드만 포함하는 목록 보기용 Serializer입니다. ProductDetailSerializer
는 id
, name
, price
, description
필드를 모두 포함하는 상세 보기용 Serializer입니다.
get_serializer_class
메서드는 요청 유형과 요청 작업에 따라 적절한 Serializer 클래스를 반환합니다. 목록 보기 요청 (self.request.method == 'GET'
and self.action == 'list'
)에는 ProductListSerializer
가 사용되고, 상세 보기 요청 (self.request.method == 'GET'
and self.action != 'list'
)에는 ProductDetailSerializer
가 사용됩니다.
from rest_framework import serializers, viewsets
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ProductDetailSerializer(ProductSerializer):
class Meta:
fields = ('id', 'name', 'price', 'description')
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
lookup_field = 'slug'
class ProductDetailViewSet(ProductViewSet):
serializer_class = ProductDetailSerializer
이 예제에서는 ProductViewSet
과 ProductDetailViewSet
두 개의 ViewSet 클래스를 정의합니다. ProductViewSet
은 기본 Serializer 클래스로 ProductSerializer
를 사용합니다. ProductDetailViewSet
은 ProductDetailSerializer
를 사용하여 상세 보기를 제공합니다.
lookup_field
매개 변수는 URL 패턴에서 사용할 조회 필드를 지정합니다. 이 경우 slug
필드가 사용됩니다. serializer_class
매개 변수는 각 ViewSet 클래스에서 사용할 Serializer 클래스를 지정합니다.
/products/{slug}
경로에 대한 요청은 ProductViewSet
으로 라우팅되고, ProductSerializer
를 사용하여 직렬화됩니다. /products-detail/{slug}
경로에 대한 요청은 ProductDetailViewSet
으로 라우팅되고, ProductDetailSerializer
를 사용하여 직렬화됩니다.
결론
Django REST Framework에서 동일한 ModelViewSet에서 서로 다른 Serializer 사용하기: 대체 방법
상속 사용하기:
하나의 기본 Serializer 클래스를 정의하고 상속을 사용하여 특정 필드를 추가하거나 제외하는 자식 Serializer 클래스를 만들 수 있습니다. 이 방법은 코드를 DRY(Don't Repeat Yourself)하게 유지하는 데 도움이 될 수 있습니다.
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ProductListSerializer(ProductSerializer):
class Meta:
fields = ('id', 'name', 'price')
class ProductDetailSerializer(ProductSerializer):
description = serializers.CharField(max_length=255)
class Meta:
fields = ('id', 'name', 'price', 'description')
위 예제에서 ProductListSerializer
는 ProductSerializer
를 상속하여 id
, name
, price
필드만 포함하도록 필드 목록을 제한합니다. ProductDetailSerializer
는 description
필드를 추가하여 ProductSerializer
를 상속합니다.
직접 직렬화 및 역직렬화 사용하기:
get_object
및 update
메서드를 오버라이드하여 직접 직렬화 및 역직렬화 논리를 구현할 수 있습니다. 이 방법은 더 많은 제어력을 제공하지만, 보다 복잡하고 코드를 유지 관리하기 어려울 수 있습니다.
from rest_framework import generics
from .models import Product
class ProductViewSet(generics.GenericViewSet):
queryset = Product.objects.all()
def get_object(self):
product = Product.objects.get(pk=self.kwargs['pk'])
return product
def list(self, request):
serializer = ProductListSerializer(self.get_queryset(), many=True)
return Response(serializer.data)
def retrieve(self, request, pk):
product = self.get_object()
serializer = ProductDetailSerializer(product)
return Response(serializer.data)
def create(self, request):
serializer = ProductSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors)
def update(self, request, pk):
product = self.get_object()
serializer = ProductSerializer(product, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors)
위 예제에서는 GenericViewSet
을 사용하여 기본적인 CRUD 작업을 구현합니다. get_object
, list
, retrieve
, create
, update
메서드를 직접 오버라이드하여 직렬화 및 역직렬화 논리를 구현합니다.
서드파티 라이브러리 사용하기:
drf-extensions
과 같은 서드파티 라이브러리를 사용하여 ModelViewSet에서 여러 Serializer를 사용하는 데 도움이 되는 추가 기능을 얻을 수 있습니다.
from rest_framework.extensions import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ProductListSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id', 'name', 'price')
class ProductDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id', 'name', 'price', 'description')
class ProductViewSet(serializers.SerializerViewSet):
queryset = Product.objects.all()
def get_serializer_class(self):
if self.action == 'list':
return ProductListSerializer
elif self.action == 'retrieve':
return ProductDetailSerializer
return ProductSerializer
django serialization django-rest-framework