Today I Learned/django

장고 ViewSet 으로 list, retrieve, update, create, delete 직접 구현하기

하나719 2023. 9. 28. 05:27
반응형

1. ModelViewSet 사용하기

장고에서 DRF를 사용하면 무려 코드 두줄로 기본 CRUD를 완성할 수 있다. 

ModelViewSet 을 상속받아서, 쿼리셋과 Serializer만 설정해주면 된다.

그리고 라우터 한줄을 추가해주면 알아서 관련된 CRUD 엔드포인트를 만들어준다.

 

[Post 예시]

# views.py
class PostViewSet(ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    
# urls.py

router = DefaultRouter()
router.register('post', views.PostViewSet, basename='post')

urlpatterns= [
	*router.urls,
]

위 코드의 PostViewSet 클래스는 ModelViewSet을 상속받아 구현되었고, 라우터를 통해 기본적인 CRUD 엔드포인트가 만들어졌다.

역할 HTTP 요청 메소드 엔드포인트
게시물 리스트 출력 GET /post/
상세 게시물 출력 GET /post/{id}
게시물 생성 POST /post/
게시물 업데이트 Put,Petch /post/{id}
게시물 삭제 DELETE /post/{id}

 

너무너무 간편하지만 안에 동작하는 코드들이 궁금해서 한번 짜보았다.

 

2. ViewSet 사용하기

ViewSet을 상속받으면 각 요청에 대한 응답을 직접 함수로 구현해서 커스텀해서 사용할 수 있다. 

 

- get 요청 시

1) 전체 리스트 출력: many=True 

2) 특정 아이템 출력: 쿼리셋 작성 시 get(pk=pk)

 

- post, put, petch

1) 아이템 생성시, serializer에 request.data 전달 

2) 아이템 수정시 serializer에 수정할 게시물 객체와 request.data 함께 전달

3) 아이템 삭제 시 삭제할 아이템 객체.delete() 수행하면 바로 삭제됨 

 

class PublicPostViewSet(ViewSet):

    def list(self, request):
        queryset = Post.objects.all()
        serializer = PostSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self,request,pk=None):
        qs = Post.objects.get(pk=pk)
        serializer = PostSerializer(qs)
        return Response(serializer.data)

    def create(self, request):
        serializer = PostSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def update(self,request, pk=None):
        qs = Post.objects.all()
        post = get_object_or_404(qs, pk=pk)
        serializer = PostSerializer(post, data=request.data)

        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors,
                            status = status.HTTP_400_BAD_REQUEST)

    def destroy(self, request, pk=None):
        queryset = Post.objects.all()
        post = get_object_or_404(queryset, pk=pk)
        post.delete()
        return Response({"message":"item deleted"}, status = 204)

 

 

3. ModelViewSet + aciton 데코레이터

이제 내부 동작을 어느정도 파악했으니, 간편하게 제공되는 ModelViewSet을 잘 활용해보자.

기본 CRUD 외에 기능을 구현하고 싶다면 action 데코레이터를 활용할 수 있다. 

 

action 데코레이터에서 두가지를 설정해줄 수 있다.

1) detail: 특정 아이템에 대한 건지, 전체 아이템에 대한건지 -> /post/ or /post/{id}

2) methods = ['']: 어떤 Http 요청에 대한건지 

 

그리고 아래 함수내에서 get_object() , get_serializer() 함수를 통해 클래스내의 object와 serializer를 간단하게 가져와서 함수내에서 사용할 수 있다. 

class PostViewSet(ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

    @action(detail=False, methods=['GET'])
    def public(self,request):
        qs = self.queryset.filter(is_public=True)
        serializer = self.get_serializer(qs, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=['PATCH'])
    def set_public(self, request, pk):
        instance = self.get_object()
        instance.is_public = True
        instance.save()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

 

코드 해설

1. public

is_public=True 인 item만 출력

-> 기본 list 출력과 거의 동일한데, filter를 활용해주었다. 

 

2. set_public

특정 아이템의 pulic 상태를 true로 업데이트 해주기

 

 

 

반응형