【问题标题】:Django REST Framework - create child of nested relationshipDjango REST Framework - 创建嵌套关系的孩子
【发布时间】:2016-01-14 18:27:18
【问题描述】:

我正在使用 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 创建我的 cmets?

【问题讨论】:

  • 为什么要重载get_querysetperform_create?如果您不这样做,我想它应该可以正常工作。请检查一下好吗?
  • 我正在重载 get_queryset 以便仅返回附加到特定帖子的 cmets,并且我正在重载 perform_create 以便我可以从 url 和用户中获取帖子编号请求(类似于此处的示例:django-rest-framework.org/api-guide/generic-views)。我会尝试删除它们,但我相信它会破坏其他功能。

标签: django django-rest-framework


【解决方案1】:

在您的 perform_create 函数中,您获得的主键是一个整数,而不是 Post 对象。此外,您不想调用 save 两次 - 这将导致保存两个模型(假设它不会引发验证错误 - 在本例中是这样)。

更好的方法可能是:

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)

【讨论】:

  • 没想到我可以在save函数里放多个参数,谢谢!我不需要添加要保存的文本,我相信因为它是由我的序列化程序类处理的。
  • 我有一个类似的问题。你能帮忙看看这个吗?stackoverflow.com/questions/62655168/…
【解决方案2】:

嗯,最明显的错误是你调用了 save() 两次,第一次是一个用户,一个是帖子。在第一次调用中,它尝试创建一个没有帖子的评论,并导致数据库给你失败的约束错误。替换

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

序列化器.save(用户=self.request.user, post=int(self.kwargs['post_pk']))

你应该没事的。

也就是说,您可能应该删除 ReadOnlyFields 并将 read_only_fields 添加到序列化程序元

类 CommentSerializer(serializers.ModelSerializer): 元类: 型号 = 评论 字段 = ('id', 'text', 'user', 'post') read_only_fields = ('post', 'user')

【讨论】:

猜你喜欢
  • 2017-03-12
  • 2015-09-18
  • 1970-01-01
  • 2021-05-29
  • 1970-01-01
  • 1970-01-01
  • 2019-05-29
  • 2019-02-19
  • 1970-01-01
相关资源
最近更新 更多