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

时间:2015-12-05 09:51:44

标签: django validation django-rest-framework

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

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

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

但发布新Review的网址中包含Book个ID,并且用户已通过身份验证:

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

现在,当我对网址执行POST操作时,DRF会抱怨book字段是必需的,即使我尝试向重载的perform_create函数发送关键字参数(见下面的片段)

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

我见过partial solution in this question,但我的问题是我不仅需要向验证程序提供当前经过身份验证的用户,还要提供book信息,因为我需要unique_together约束。

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

所以我的问题是当unique_together信息嵌入book并且url信息是其中的一部分时,如何验证来自用户请求的输入数据user传入request(虽然这两个都是相关的外键而不是Review模型的本地属性)?

以下是我的模型和序列化器:

models.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"),)

serializers.py

class ReviewSerializer(serializers.ModelSerializer):

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

    class Meta:
        model = Review

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

urls.py

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

1 个答案:

答案 0 :(得分:1)

你正试图让事情变得更加艰难。

我对这个问题的看法是,独特的约束约束是业务规则的一部分。因此,我要去除序列化器上的约束。在序列化程序验证了数据后,您将能够检查审核上的约束(所有者+书籍)并在已经存在的情况下提出验证错误。在保存序列化器之前在perform_create中执行此操作似乎是明智的。

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

class ReviewSerializer(serializers.ModelSerializer):

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

    class Meta:
        model = Review
        validators = []

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