Django REST框架 - 创建嵌套关系的子代

时间:2016-01-14 18:27:19

标签: django django-rest-framework

我正在为一个允许用户创建帖子并对这些帖子发表评论的网站使用Django Rest Framework构建API。我可以从API创建帖子,但是当我尝试创建评论时,我收到以下错误:

NOT NULL约束失败:app_comment.post_id

我的模特:

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)

和我的评论序列化器:

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')

和我的评论观点:

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'])

尝试在帖子上创建评论时,我会看到正在打印出的正确信息(即'在帖子6上创建用户评论:发布对象')。

为什么我的评论没有使用正确的post_id创建?

2 个答案:

答案 0 :(得分:2)

在perform_create函数中,您将获得一个整数而不是Post对象的主键。此外,您不希望两次调用保存 - 这将导致保存两个模型(假设它不会抛出验证错误 - 在这种情况下就是这样)。

更好的方法可能是:

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

此外,您可能还希望将文本内容添加到您正在保存的模型中。所以也许,所以你可能需要添加/更改它来阅读:

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

虽然我正在考虑这个问题 - 但您可能希望保存一个“获取”的电话。并避免访问数据库并直接指定外键。您可以使用以下语法执行此操作:

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)

答案 1 :(得分:0)

嗯,最明显的错误是你两次调用save(),首先是用户,有一个帖子。并且在第一次调用中,它尝试创建没有帖子的注释,并使数据库为您提供失败的约束错误。替换

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

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

你应该没事。

那就是说,您应该删除ReadOnlyFields并将read_only_fields添加到序列化器元

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