假设我的应用程序中有三个模型,用户可以为一本书撰写评论。要求是每个用户只能对每本书进行一次审核。
Review
模型有User
和Book
模型的两个外键。我希望能够在创建Review
模型实例之前验证用户输入,以确保用户无法为每本书创建多个评论。
如果我要求用户在发送到DRF版本3的数据中提供User
和Book
信息,我知道该怎么做。
但发布新Review
的网址中包含Book
个ID,并且用户已通过身份验证:
网址已用于list
和create
评论:/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
模型的本地属性)?
以下是我的模型和序列化器:
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"),)
class ReviewSerializer(serializers.ModelSerializer):
book = serializers.PrimaryKeyRelatedField(read_only=True)
user = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Review
class ReviewList(generics.ListCreateAPIView):
serializer_class = ReviewSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user, book=self.kwargs['book_id'])
url(r'^book/(?P<book_id>\d+)/reviews/$', view=ReviewList.as_view(), name='review-list')
答案 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 = []
确保在进行更改之前打印序列化程序实例,以确保您不会删除其他约束。