ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Django REST Framework를 이용해 중첩 댓글 구성하기
    DRF(Django REST Framework) 2020. 1. 15. 13:34
    • 게시글에 대한 댓글은 ForeignKey를 이용해 간단하게 구현할 수 있다. 하지만 댓글에 대한 댓글, 또 그 댓글에 대한 대댓글 등 중첩으로 댓글을 구현하기 위해서는 model을 생성할 때 자신(댓글)을 부모로 참조하여 구성해야 한다.
    • 데이터베이스는 입력 순서대로 id를 부여하고 데이터를 저장하기 때문에 댓글(부모)에 대한 댓글(자식)을 작성할 경우, 자식 댓글은 부모 댓글의 밑이 아닌 테이블의 가장 아래에 저장하게 된다. 
    • Front-end에서 댓글의 queryset을 부모-자식 관계에 맞게 화면에 출력하거나, Back-end에서 관계에 맞게 정리하여 Front-end에 전달할 수 있다.
    • 이 포스트는 Back-end에서 중첩 댓글을 순서 및 관계에 맞게 정리하여 전달하는 방법을 작성하였다.
    # models.py
    class Comment(models.Model):
        product = models.ForeignKey(Product, related_name='comments', on_delete=models.CASCADE)
        user = models.ForeignKey(User, related_name='users', on_delete=models.CASCADE)
        parent = models.ForeignKey('self', related_name='reply', on_delete=models.CASCADE, null=True, blank=True)
        body = models.CharField(max_length=100)
        created = models.DateTimeField(auto_now_add=True)

     

    • 최상위 댓글(parent=None)을 이용해 하위 댓글을 불러온다.
    # views.py
    class CommentList(ListCreateAPIView):
        serializer_class = CommentSerializer
    
        def get_queryset(self):
            queryset = Comment.objects.filter(parent=None)
            ...
    
    # serializers.py
    # to_represenstation을 오버라이딩해서 화면에 출력하는 방법
    class RecursiveSerializer(serializers.Serializer):
        def to_representation(self, instance):
            serializer = self.parent.parent.__class__(instance, context=self.context)
            return serializer.data
    
    
    class CommentSerializer(serializers.ModelSerializer):
        reply = serializers.SerializerMethodField()
        # reply = RecursiveSerializer(many=True, read_only=True)
        product = serializers.SlugRelatedField(queryset=Product.objects.all(), slug_field='name')
        
        class Meta:
            model = Comment
            fields = ('id', 'user', 'product', 'parent', 'body', 'reply')
        
        def get_reply(self, instance):
        	# recursive
            serializer = self.__class__(instance.reply, many=True)
            serializer.bind('', self)
            return serializer.data
    • instance.reply를 통해 자식 댓글을 불러오고, self.__class__를 통해 직렬화가 이루어진다.
      • 직렬화 과정 중 self.__class__ (직렬화) -> get_reply 호출 -> self.__class__ (직렬화) -> get_reply 호출... 재귀가 일어난다.
    • serializer.bind('', self)는 직렬화된 자식을 부모에게(필드 인스턴스 - reply) 연결한다.

    중첩 댓글 결과

     

    • 재귀를 이용하기 때문에 댓글의 양이 많고 복잡하게 얽혀있을 경우 페이지를 출력하기 위해 많은 자원을 소모할 수 있다. 
    • Third party library인 drf-serializer-cache를 이용해 직렬화 과정중 발생하는 속도 저하를 개선시킬 수 있다.

     

    [참고] 
    drf-serializer-cache 0.3.3 - https://pypi.org/project/drf-serializer-cache/

    댓글

Designed by Tistory.