TypeError Django REST Framework에서 댓글 작성 시 발생하는 Comment.objects.create() 오류

TypeError Django REST Framework에서 댓글 작성 시 발생하는 Comment.objects.create() 오류

·

2 min read

TypeError: Comment() got unexpected keyword arguments

Serializers.py

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'
        read_only_fields = ['post']

Views.py

    def post(self, request, post_id):
        post = self.get_object(post_id)
        serializer = CommentSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save(post=post)
            return Response(serializer.data, status=200)

위의 코드로 postman을 돌리면 아래의 이미지와 같이 user nickname,
user id, post id와 같이 자동으로 입력되어야 하는 값들도 작성하게 되어있다.

serializers.py를 보면 읽기전용 필드가 read_only_fields = ['post']만 되어있어

['post_id', 'user_id', 'user_nickname']로 변경해준다.

read_only_fields = ['post_id', 'user_id', 'user_nickname'] 로 해두면
클라이언트들이 수정이 불가능하며, 해당 필드들은 서버에서 자동으로 설정된다.


다시 postman을 돌려보면 content 필드만 필수라고 나온다.

content 필드를 넣어서 구동을 시키면 아래의 오류가 나온다.

CommentSerializer에서 Comment.objects.create() 메서드 호출 시 잘못된
키워드 post가 전달되어 발생했다.

필드를 읽기전용으로 설정하거나 create() 메서드를 사용하여 해결할 수 있다.

해당 오류는 CommentSerializer를 통해 save() 메서드를 호출할 때 발생하는 오류로 save() 메서드는 내부적으로 Comment.objects.create()를 호출하여 새로운 인스턴스를 생성한다. 이과정에서 validated_data에 포함된 post 키워드가 잘못된 인수로 전달되어 오류가 발생한 것이다.


create 메서드를 사용하여 post, user, user_nickname 필드를 직접 설정하여 준다.

Serializers.py

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'
        read_only_fields = ['post_id', 'user_id', 'user_nickname']

    def create(self, validated_data):
        request = self.context.get('request')
        post = validated_data.pop('post')
        user = request.user
        comment = Comment.objects.create(
            post_id=post,
            user_id=user,
            user_nickname=user.nickname
        )
        return comment

Views.py

   def post(self, request, post_id):
        post = self.get_object(post_id)
        serializer = CommentSerializer(data=request.data, context={'request': request})
        if serializer.is_valid(raise_exception=True):
            serializer.save(post=post_id)
            return Response(serializer.data, status=200)

위의 방법으로 로직을 수정하면

Cannot assign "6": "Comment.post_id" must be a "Post" instance.
오류가 나온다.

이는 Comment 모델의 post_id 필드에 Post 인스턴스가 아닌 post_id값을 전달하려고 해서 발생한 오류이다.

post_id 대신 post를 전달해줘야 한다.


Serializers.py

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'
        read_only_fields = ['post_id', 'user_id', 'user_nickname']

    def create(self, validated_data):
        request = self.context.get('request')
        post = self.context.get('post')
        user = request.user

        comment = Comment(
            post_id=post,  
            user_id=user,  
            user_nickname=user.nickname,
            **validated_data
        )
        comment.save()
        return comment

post_id대신 post인스턴스를 직접 할당하도록 수정한다.

이는 Comment 모델의 post_id 필드에 Post 인스턴스가 아닌 post_id값을 전달하려고 해서 발생한 오류로

post_id 대신 post를 전달해야 한다.

create 메서드에서 post를 직접 할당하여 Comment 객체를 생성한다.

post 인스턴스를 사용하여 올바른 외래키 관계를 설정한다.

Views.py

    def post(self, request, post_id):
        post = self.get_object(post_id)
        serializer = CommentSerializer(data=request.data, context={'request': request, 'post': post})
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data, status=200)

context로 post 인스턴스를 CommentSerializer에 전달하여 create 메서드에 접근할 수 있게 한다.

CommentSerializer에서 create() 메서드를 정의하여 post와 관련된 데이터는 Post 모델의 인스턴스를 직접 할당하도록 수정

view에서 post 인스턴스를 serializer에 context로 전달해 create() 메서드가 올바른 값으로 댓글을 생성할 수 있게 함