【问题标题】:Django Rest Framework - "unique_together" internal server error. How to respond with errorDjango Rest Framework - “unique_together”内部服务器错误。如何响应错误
【发布时间】:2022-02-08 10:35:26
【问题描述】:

我目前有一个名为“Review”的模型,其中我有一个“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."
    ]
}

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

【问题讨论】:

  • 试试这个,unique_together = ['user__id', 'post__id']
  • @satyajit 这似乎不正确,我收到以下错误“posts.Review: (models.E012) 'unique_together' 指的是不存在的字段 'post__id'。”

标签: django django-models django-rest-framework


【解决方案1】:

尝试使用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() 方法

【讨论】:

  • 谢谢,如果不是在请求正文中提供它作为 API 端点 url 的 kwarg 提供它,是否有办法为我的“post”字段做同样的事情?我更改了我的代码,所以 url 看起来像这样:example.com/api/posts//review/create/ 在我的 perform_create 中有这个: def perform_create(self, serializer): post_pk = self. kwargs['pk'] post= get_object_or_404(Post, id=post_pk) serializer.save(post=post)
  • 我创建了一个新问题以使事情更清楚:stackoverflow.com/questions/65558075/…
猜你喜欢
  • 2013-08-02
  • 1970-01-01
  • 2021-01-12
  • 2023-03-25
  • 2011-03-18
  • 2018-06-20
  • 2013-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多