Django RestFramework 에서 copy 기능을 구현
(현재 다른 미션이 있어서 일단은 코드 포스팅만을 진행)
□ views.py
class ProductCopyInstance(APIView):
serializer_class = ProductSerializer
def get_object(self, pk):
try:
return Product.objects.get(pk=pk)
except Product.DoestNotExist:
raise Http404
def get(self, request, pk, format=None):
response = self.get_object(pk=pk)
serializer = ProductSerializer(response)
return Response(serializer.data)
def post(self, request, pk, format=None, **kwargs):
"""
복사하여 새로운 객체를 만들어주기 때문에 POST 메서드로 사용하기 도전
그럼 instance=request.data 와 같이 어떤 객체인지를 먼저 알게 해줘야 할 듯
"""
# 현재 해당하는 객체의 pk 가 무엇인지까지 확인
# kwargs 는 해당하는 딕셔너리에서 key 값만을 불러옴
# POST 메서드에서 data 를 불러오면 새로 입력한 값들이 들어오기 때문에 .data 는 피해야 함
# original_data = self.kwargs.get('pk', '')
# 생성하려는 객체를 만들기 위해 우선 Product 모델에서 불러오기(아직 직렬화 상태 아님)
product = Product.objects.get(pk=pk)
product.pk = None
# 직렬화 상태(serializer) 로 만듦
# 이 클래스에서 get 메서드를 통해 들어온 request.data 를 data 로 받아 직렬화
# 매직메서드 __dict__ 의 사용방법은 느낌적으로 옳지 않은 것 같지만 일단은 구현을 위해 사용
serializer = ProductSerializer(product, data=product.__dict__)
additional_data = serializer
if additional_data.is_valid():
# save() 함수를 사용하기 위해서는 is_valid() 가 필수(아니면 에러 발생)
additional_data.save()
return Response(additional_data.data, status=status.HTTP_201_CREATED)
return Response(additional_data.errors, status=status.HTTP_400_BAD_REQUEST)
□ Django ORM CookBook 에서 아이디어를 얻은 인스턴스를 copy 하는 방법
>> Product.objects.all().count()
# 4
>> coffee = Product.objects.first()
>> coffee.pk = None
>> coffee.save()
>> Product.objects.all().count()
# 5
□ urls.py
- 가장 논의가 많이 될 것 같은 해당 자원에 접근하는 URI 이다.
- 주석에서도 설명한 듯이 자원에 대해 POST, GET, PUT, DELETE 는 REST 에서 확인할 수 있지만 객체를 copy 한다는 메서드가 정의되어 있지가 않다. 그렇기 때문에 RESTful 의 원칙에는 위배될 수 있지만 실수를 줄이고 명시적으로 하기 위해서는 이 방법이 맞지 않을까라고 지금 순간에는 생각한다.
urlpatterns = [
path('products/', views.ProductList.as_view()),
# 자원에 대한 행위(method) 를 보여주지 않는 것이 원칙이라고 한다.
# 그러나 copy 를 명시하지 않으면 DRF 에서는 어떤 기능을 하는지 구현을 해봐야 알 수 있다는 것
path('products/<int:pk>/copy/', views.ProductCopyInstance.as_view()),
path('products/<int:pk>/', views.ProductDetail.as_view()),
]