如何验证模型的两个(外键)相关字段的共同唯一性?

lis*_*oss 5 django validation django-rest-framework

假设我的应用程序中有三个模型,可让用户为一本书撰写评论。要求是每个用户只能对每本书进行一次评论。

Reviewmodel 有两个外键UserBookmodels。我希望能够在创建模型实例之前验证用户输入Review,以确保用户不能为每本书创建多个评论。

如果我要求用户提供发送到 DRF 版本 3.+ 的数据中的User和信息,我知道该怎么做。Book

但是发布新内容的 url中Review包含Bookid,并且用户已通过身份验证:

用于listcreate评论的网址:/book/{book_id}/reviews/

现在,当我对POSTurl 执行操作时,DRF 抱怨该book字段是必需的,即使我尝试将关键字参数发送到重载perform_create函数(请参阅下面的代码片段)

我的猜测是我应该将嵌入在网址中的有关书籍和评论的信息发送request到默认值UniqueTogetherValidator,但我不知道该怎么做!

我在这个问题中看到了部分解决方案,但我的问题是我不仅必须向验证器提供当前经过身份验证的用户,而且还必须提供信息book,因为我需要unique_together约束。

  • 我曾尝试default向田地提供 kwarg,但没有成功。
  • 还尝试在序列化器中提供自定义验证器,但没有成功。

所以我的问题是,当信息嵌入并且信息是传入的一部分时,如何验证unique_together用户请求的输入数据(而这两者都是相关的外键而不是模型的本地属性)?bookurluserrequestReview

这是我的模型和序列化器:

模型.py

class Review(models.Model):

    # Relationships
    book = models.ForeignKey(Book)
    user = models.ForeignKey(User)
    comment = models.TextField(null=True, blank=True)

    class Meta:
        unique_together = (("user", "book"),)
Run Code Online (Sandbox Code Playgroud)

序列化器.py

class ReviewSerializer(serializers.ModelSerializer):

    book = serializers.PrimaryKeyRelatedField(read_only=True)
    user = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Review
Run Code Online (Sandbox Code Playgroud)

部分views.py

class ReviewList(generics.ListCreateAPIView):
    serializer_class = ReviewSerializer
    def perform_create(self, serializer):
        serializer.save(user=self.request.user, book=self.kwargs['book_id'])
Run Code Online (Sandbox Code Playgroud)

urls.py

url(r'^book/(?P<book_id>\d+)/reviews/$', view=ReviewList.as_view(), name='review-list')
Run Code Online (Sandbox Code Playgroud)

Lin*_*via 2

你试图让事情变得比他们应该做的更困难。

我对这个问题的感觉是,独特的共同约束是业务规则的一部分。因此,我会消除对序列化器的限制。序列化器验证数据后,您将能够检查评论(所有者+书籍)的约束,并在已有验证错误的情况下引发验证错误。在保存序列化器之前在 Perform_create 中执行此操作似乎是明智的。

要删除唯一的一起约束,您必须在序列化器上显式设置验证器:

class ReviewSerializer(serializers.ModelSerializer):

    book = serializers.PrimaryKeyRelatedField(read_only=True)
    user = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Review
        validators = []
Run Code Online (Sandbox Code Playgroud)

确保在进行更改之前打印序列化程序实例,以便确保不会删除其他限制。