Alex
Alex

Reputation: 625

How to post with references in Django Rest Framework

I have Comment model related with User model

# models.py
class Comment(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    more fields...
    ....

In the serializer I want to do a create (POST) of a user comment. But the post method is not enabled, only the put or patch method

Example: User Jon wants to create a comment

# serializers.py

class CommentSerializer(serializers.ModelSerializer):
  class Meta:
    model = Comment
    fields = '__all__'

class UserCommentSerializer(serializers.ModelSerializer):
    # id of comment
    url = serializers.HyperlinkedIdentityField(
        view_name="user-comments-detail",
        read_only=True
    )    
    id = serializers.CharField(read_only=True)
    comment = CommentSerializer()
    class Meta:
        model = User
        fields = ['id', 'comment']

    def create(self, validated_data):
        comment_data = validated_data.pop('comment')
        user = User.objects.create(**validated_data)
        Comment.objects.create(user=user, **comment_data)
        return user

I want to new comment, referencing the user

# views.py
class CommentViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserCommentSerializer

But I have an exception, that the user has no comment RelatedObjectDoesNotExist

My url like this

http://localhost:8000/user-comments/10

10 is a user_id pk

{} object post

Example: Comment.objects.create(user=pk, {})

Currently, only put and patch is enabled, but what I want to do is post of user

{
    "url": "http://localhost:8000/user-comments/10",
    "id": "10",
    "comment": null
}

Comment does not exist

Any idea or suggestion?

Upvotes: 0

Views: 181

Answers (2)

Guillaume
Guillaume

Reputation: 2006

You actually need just one serializer for that.

This will create a comment for the current logged in user.

# serializers.py

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

    def create(self, validated_data):
        # get the user who sent the request
        user = self.context['request'].user
        return Comment.objects.create(user=user, **validated_data)


# views.py

class CommentViewSet(viewsets.ModelViewSet):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer

    def get_serializer_context(self):
        # this is important since you want to pass the request object to your serializer
        context = super().get_serializer_context()
        context.update({"request": self.request})
        return context

Upvotes: 1

HuLu ViCa
HuLu ViCa

Reputation: 5452

The exception you are getting is because ModelSerializer is linked to a specific model, in this case you linked UserCommentSerializer to model User. Variable Meta.fields specifies which fields of the model are being returned by the serializer and, so, you are getting an exception because such variable is set to ('id', 'comment') and model User doesn't have a field comment.

You can achieve what you want, this way:

class UserCommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id']
        extra_kwargs = {'comment': {'write_only': True}}

    def create(self, validated_data):
        comment_data = validated_data.pop('comment')
        user = User.objects.create(**validated_data)
        Comment.objects.create(user=user, comment=comment_data)

Upvotes: 0

Related Questions