TIL(22/12/05)

김규현·2022년 12월 5일
0

💻 Today I Learned

drf에서 게시글의 댓글을 작성하는 View와 Serializer를 만든 후 포스트맨으로 댓글을 작성했더니 게시글의 내용이 변경되는 상황이 발생했다.

우선 코드는 아래와 같이 작성했다.

# models.py
class Article(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='article_user')
    category = models.ForeignKey(Hobby, on_delete=models.CASCADE, related_name='article_category')
    title = models.CharField(max_length=500)
    content = models.TextField()
    article_image = models.ImageField(upload_to='media/article/', null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.title)


class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comment_article')
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='comment_user')
    content = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.content)

# views / 게시글의 댓글 작성
class CommentView(APIView):
	def post(self, request, article_id):
    	article = get_object_or_404(Article, id=article_id)
        serializer = CommentCreateSerializer(article, data=request.data)
        if serializer.is_valid():
            serializer.save(user=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        
# serializers.py
class CommentCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ('content',)

구글링을 해보니 내가 작성한 CommentView의 deserializing 방식이 잘못 작성 되었음을 깨달았다.

나는 게시글을 특정하고 해당 게시글에 댓글을 작성해야 한다는 생각때문에 article 변수에 get_object_or_404로 Article 모델의 id 값으로 찾은 instance를 담아주었고, 해당 instance를 serializer에 대입하여 내가 댓글을 작성할 게시글을 특정하고 data를 request.data를 넣어 댓글을 작성할 수 있다고 생각했다.

하지만 그건 개념 자체가 틀린 방식이었고, serializer. save()를 통해 호출할 때 인스턴스의 생성이나 수정이 이루어지는데, 어떻게 로직이 이루어지는지를 정하기 위해 create()와 update()를 사용한다.

# create 메서드
serializer = CommentCreateSerializer(data=data)

위의 경우 인자가 하나밖에 없기 때문에 create() 로직이 사용되어 create 메서드에 의해 db에 인스턴스가 생성된다.

# update 메서드
serializer = CommentCreateSerializer(comment, data=data)

또 다른 예로 위의 경우에는 인자가 둘이기 때문에 update()로직이 사용되어 db에 저장된 인스턴스의 값이 수정된다.

즉 serializer에 들어가는 인자로는 data와 모델 instance인데 data만 입력했을 때는 모델의 instance가 생성되어 db에 저장되고, data와 입력과 함께 모델의 instance를 넣어주었을 때는 update가 되기 때문에 해당 instance의 값이 수정된다.

나의 경우에는 CommentView에서 article_id를 받아 Article 모델로 생성된 인스턴스 중 id 값이 일치한 인스턴스를 article 변수에 담았고 이 article을 serializer에 넣어주었기 때문에 article이 수정되었던 것이다.

이 문제를 해결하기 위해 serializer에서 create 메서드가 실행되도록 data만 넣어주었고, serializer를 save() 할 때 article_id를 대입하여 댓글을 작성할 게시글을 특정하고, user를 requet.user를 대입하여 댓글을 작성하는 user가 누군지 설정해주었다.

class CommentView(APIView):
def post(self, request, article_id):
        serializer = CommentCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(article_id=article_id, user=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
profile
웹개발 회고록

0개의 댓글