0

I'm building an API with the Django Rest Framework for a site that allows users to create posts, and comment on those posts. I'm able to create posts from the API fine, but when I try to create a comment I get the following error:

NOT NULL constraint failed: app_comment.post_id

my models:

class Post(models.Model):
    owner = models.ForeignKey('auth.User', related_name = 'posts')
    post_title = models.CharField(max_length=200)
    post_description = models.CharField(max_length=1000)

class Comment(models.Model):
    user = models.ForeignKey(User, related_name = 'comments')
    post = models.ForeignKey(Post, related_name = 'comments')
    text = models.CharField(max_length=1000)

and my comment serializer:

class CommentSerializer(serializers.ModelSerializer):
    user = serializers.ReadOnlyField(source='user.username')
    post = serializers.ReadOnlyField(source='post.id')
    class Meta:
        model = Comment
        fields = ('id', 'text', 'user', 'post')

and my comment view:

class PostCommentList(generics.ListCreateAPIView):
    permission_classes = (permissions.IsAuthenticated,
                            IsOwnerOrReadOnly,)
    serializer_class = CommentSerializer
    def get_queryset(self):
        post = self.kwargs['post_pk']
        post = Post.objects.get(pk = post)
        return post.comments.all()
    def perform_create(self, serializer):
        post = self.kwargs['post_pk']
        print("creating a comment from " + str(self.request.user) + " on post " + str(post) +" : "+ str(Post.objects.get(pk = post)))
        serializer.save(user = self.request.user)
        serializer.save(post = self.kwargs['post_pk'])

When attempting to create a comment on a post, I see the correct information being printed out (i.e. 'creating a comment from user on post 6 : Post object').

Why are my comments not being created with the correct post_id?

2
  • Why are you overloading get_queryset and perform_create? I guess it should work normally if you don't do it. Could you check it, please? Commented Jan 14, 2016 at 18:31
  • I'm overloading get_queryset so that the only the comments attached to a specific post will be returned, and I'm overloading perform_create so that I can get the post number form the url and the user from the request (similar to the example here: django-rest-framework.org/api-guide/generic-views). I'll try removing them, but I believe it will break other functionality. Commented Jan 14, 2016 at 18:54

2 Answers 2

2

In your perform_create function you are getting the primary key which is an integer, not a Post object. Also, you don't want to call save twice - it will result in saving two models (assuming it doesn't throw validation errors - which in this case it is).

A better way to do this might be:

post_pk = self.kwargs['post_pk']
post = Post.objects.get(pk = post_pk)
serializer.save(user=self.request.user, post=post)

Also you'll probably want to add the text content to the model you are saving as well. So perhaps, so you may need to add/change it to read:

text = self.kwargs['text']
serializer.save(user=self.request.user, post=post, text=text)

While I'm thinking of it - you may want to save a call to 'get' and avoid a trip to the database and specify the foreign key directly. You can do that using this syntax:

post_pk = self.kwargs['post_pk']
# Note - we won't call '.get' here
serializer.save(user=self.request.user, post_id=post_pk, text=text)
Sign up to request clarification or add additional context in comments.

2 Comments

Didn't realize I could put multiple parameters in the save function, thanks! I don't need to add the text to save though, I believe because it is handled by my serializer class.
I have a similar issue to this.Can you help look into this please?stackoverflow.com/questions/62655168/…
0

Well, the most obvious error is that you are calling save() twice, first with a user and the with a post. And in the first call it tries to create a comment without a post and causes the database to give you the failed constraint error. Replace

serializer.save(user = self.request.user)
serializer.save(post = self.kwargs['post_pk'])

with

serializer.save(user=self.request.user,
                post=int(self.kwargs['post_pk']))

and you should be fine.

That said, you should probably remove the ReadOnlyFields and just add read_only_fields to the serializer meta

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ('id', 'text', 'user', 'post')
        read_only_fields = ('post', 'user')

1 Comment

This looks similar to the issue I'm having presently. Can you help look into it please stackoverflow.com/questions/62655168/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.