首页 > 解决方案 > Django Rest Framework - “unique_together”内部服务器错误。如何响应错误

问题描述

我目前有一个名为“评论”的模型,其中我有一个“unique_together”约束,因此一个用户每篇文章只能写一篇评论。

class Review(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(User, related_name='reviews', on_delete=models.SET_NULL, null=True)
    post = models.ForeignKey(Post, related_name='reviews', on_delete=models.CASCADE)
    rating = models.IntegerField()
    comment = models.TextField(blank=True, null=True)

    class Meta:
        unique_together = ['user', 'post']

在我的视图中,我从请求中获取用户(我正在使用令牌身份验证)并使用该用户通过覆盖“perform_create”方法来保存对象:

class ReviewCreateView(CreateAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = ReviewCreateSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

我的序列化器看起来像这样:

class ReviewCreateSerializer(ModelSerializer):
    class Meta:
        model = Review
        fields = ['post', 'rating', 'comment']

当我尝试向同一用户的同一帖子提交两条评论时,我收到内部服务器错误。

我的 HTTP POST 请求的正文如下所示:

{
    "post" : 11,
    "rating": 1,
    "comment": "this is a great post"
}

而不是得到错误响应(例如 403 错误)。我得到了这个 Django 服务器错误:

django.db.utils.IntegrityError: duplicate key value violates unique constraint

在花了一些时间研究之后,我看到 Django Rest Framework 提供了“UniqueTogetherValidator”。所以我像这样添加它:

class ReviewCreateSerializer(ModelSerializer):
    class Meta:
        model = Review
        fields = ['post', 'rating', 'comment']
        validators = [
                UniqueTogetherValidator(
                    queryset=Review.objects.all(),
                    fields=['user', 'post']
                )
            ]

但是我遇到的问题是它出错,因为它找不到关键的“用户”,我猜是因为我的 HTTP 请求正文中没有“用户”字段(因为用户被抓住了Django 使用身份验证令牌)。我收到以下错误:

KeyError: 'user'

我还尝试将“用户”添加到我的序列化器字段中:

fields = ['user', 'post', 'rating', 'comment']

但我收到以下错误响应:

{
    "user": [
        "This field is required."
    ]
}

我真的很感激一些帮助来解决这个问题。非常感谢!

标签: djangodjango-modelsdjango-rest-framework

解决方案


尝试使用CurrentUserDefault序列化程序字段,以便可以隐式检索用户以进行验证。

class ReviewCreateSerializer(ModelSerializer):
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    class Meta:
        model = Review
        fields = fields = ['user', 'post', 'rating', 'comment']
        validators = [
                UniqueTogetherValidator(
                    queryset=Review.objects.all(),
                    fields=['user', 'post']
                )
            ]

此外,有了这个,您不再需要将用户传递给序列化程序保存方法,因为它已经存在于序列化程序中。因此,您可以摆脱perform_create()视图中的覆盖方法


推荐阅读