[DRF] PostDetail 리팩토링

Jinhyung Rhee·2022년 8월 18일
0

Now : /api2/post/1 (RetrieveAPIView) 출력 형식

  • 문제1) 현재 post 내용만 출력되고 있음 -> prevPost, nextPost, commentList 필요!
  • 문제2) category와 tag가 pk로 표현되고 있음

Target : /api/post/1 출력 형식

  • post -> Post 모델에 관한 serializer 사용
  • prevPost, nextPost : Post 모델에 관한 serializre를 사용하지만 'id'와 'title'만 가져오면 됨!
  • commentList : Comment 모델에 관한 serializer를 사용, List로 되어있으므로 many=True 인자를 주면 됨!
  • Nested Serializer 사용!

코드 작성

  • serializers.py 수정 : PostSerializerDetail()

    class PostSerializerSub(serializers.ModelSerializer):
        class Meta:
            model = Post
            fields = ['id', 'title']
    
    class CommentSerializerSub(serializers.ModelSerializer):
        class Meta:
            model = Comment
            fields = ['id', 'content', 'update_dt']
    
    # 일반 serializer 상속 -> 키(필드)를 직접 설정하는 경우
    class PostSerializerDetail(serializers.Serializer):
        post = PostRetrieveSerializer()
        prevPost = PostSerializerSub() # id와 title만 가져옴
        nextPost = PostSerializerSub() # id와 title만 가져옴
        commentList = CommentSerializerSub(many=True) # 일부 필드만 사용하는 serializer('id', 'content', 'update_dt')
    • 실제로 client에게 내려주는 정보를 만드는 serializer는 PostSerializerDetial임 -> 그 안에 여러 개의 mini serializer들로 구성됨!(Nested Serializer)
    • 왼쪽은 key, 오른쪽은 value가 들어갈 serializer(=type)들로 구성
    • post = PostRetrieveSerializer() : Post 모델의 전체 내용이 들어가야 하므로 PostRetrieveSerializer 사용
    • prevPost = PostSerializerSub() : Post 모델의 일부 필드('id', 'title')만 가져오는 PostSerializerSub 만들어서 사용 (nextPost도 동일!)
    • commentList = CommentSerializerSub(many=True) :
      • Comment 모델의 일부 필드('id', 'content', 'update_dt')만 가져오는 CommentSerializerSub 만들어서 사용
      • List 형식으로 여러 개의 Comment가 나와야 하므로 many=True 옵션 사용!
  • views.py 수정 : PostRetrieveAPIView()

    # get_xxx_by_update_dt 메서드 exception 처리 함수
    def get_prev_next(instance):
      try:
        prev = instance.get_previous_by_update_dt()
      except instance.DoesNotExist:
        prev = None
    
      try:
        next_ = instance.get_next_by_update_dt()
      except instance.DoesNotExit:
        next_ = None
    
      return prev, next_
    
    # PostRetrieveAPIView 수정
    class PostRetrieveAPIView(RetrieveAPIView):
      queryset = Post.objects.all()
      serializer_class = PostSerializerDetail
    
      # overriding
      def retrieve(self, request, *args, **kwargs):
            instance = self.get_object()
            # prevInstance = instance.get_previous_by_update_dt() # update_dt를 기준으로 앞에 있는 인스턴스를 가져오는 메서드(built-in)
            # nextInstance = instance.get_next_by_update_dt() # update_dt를 기준으로 뒤에 있는 인스턴스를 가져오는 메서드
            prevInstance, nextInstance = get_prev_next(instance)
            commentList = instance.comment_set.all() # 현재 post에 달려있는 comment 전부 가져오는 ORM 쿼리문
            # 데이터를 준비해서 serializer type에 맞게 데이터를 공급해야 함!⭐⭐⭐
            data = {
              'post' : instance,
              'prevPost' : prevInstance,
              'nextPost' : nextInstance,
              'commentList' : commentList,
            }
            serializer = self.get_serializer(instance=data) # 테이블에서 가져온 데이터를 serializer에 공급
            return Response(serializer.data) # serializer.data 에서 '직렬화' 과정이 이루어짐! **
    • serializer_class = PostSerializerDetail : 출력 결과는 PostSerializerDetail을 통해 보여줌(= PostSerializer로 직렬화!)

    • RetrieveAPIView를 오버라이딩하기 위해 소스 코드 살펴보기 (RetrieveAPIView > RetrieveModelMixin)

      • instance = self.get_object() : 테이블로부터 인스턴스 가져옴
      • serializer = self.get_serializer(instance) : 가져온 데이터(인스턴스)를 serializer에 공급
        • 이때 직렬화가 이루어지는 것은 아님!⭐
      • return Response(serializer.data) : 직렬화된 데이터를 client
        • serializer.data가 호출될 때 직렬화가 이루어짐!⭐
    • instance.get_previous_by_update_dt() : 'update_dt' 기준으로 앞에 있는 인스턴스를 가져오는 메서드 (Django 기본 제공)

      • 맨 처음 인스턴스에서 호출 시 에러 발생 -> 예외처리 필요!
    • instance.get_next_by_update_dt() : 'update_dt' 기준으로 다음에 있는 인스턴스를 가져오는 메서드 (Django 기본 제공)

      • 맨 뒤 인스턴스에서 호출 시 에러 발생 -> 예외처리 필요!
        • by_FOO : FOO는 DateFieldDateTimeField이어야 함!(링크)
    • commentList = instance.comment_set.all() : 인스턴스(Post 객체)에 달려있는 comment_set을 전부 가져오는 메서드 (ForeignKey)

결과 확인

  • Browsable API

  • JSON

    • TODO : image url과 category 수정 필요!

Reference

https://www.inflearn.com/course/%EC%9E%A5%EA%B3%A0-drf/dashboard

profile
기록하는 습관

0개의 댓글