DRF 3.0:UniqueTogetherValidator具有只读字段

bay*_*lee 7 django-rest-framework

在从2.4.4升级到Django REST Framework 3.0的过程中我希望有一个只读用户字段,但这是失败的,因为UniqueTogetherValidator需要'user'(我认为)

我有模型(借口错别字,这是简化的,代码工作正常IRL):

class ExampleModel(models.Model):
    some_attr = models.PositiveSmallIntegerField()
    other_attr = models.PositiveSmallIntegerField()
    user = models.ForeignKey(User)

    class Meta:
        unique_together = ('some_attr', 'other_attr', 'user')
Run Code Online (Sandbox Code Playgroud)

视图集:

class ExampleViewSet(viewsets.ModelViewSet):
    queryset = ExampleModel.objects.all()
    serializer_class = ExampleSerializer

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

    def perform_update(self, serializer):
        serializer.save(user=self.request.user)
Run Code Online (Sandbox Code Playgroud)

串行:

class ExampleSerializer(serializers.ModelSerializer):
    user = UserSerializer(read_only=True)

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

现在,我不断收到错误说:{"user":["This field is required."]}以前的情况并非如此.在具有相同基本问题的稍微不同的示例中,May not set both 'read_only' and 'required'即使我没有按要求设置用户,我也会收到断言错误.

无论是否required=False在序列化程序中添加用户属性,或者如果我将用户添加到序列化程序元数据中的排除字段,我都会收到相同的错误.

当我使用方便的新串行器打印时,我看到:

class Meta:
    validators = [UniqueTogetherValidator(queryset=ExampleModel.objects.all(), fields=('user', 'some_attr', 'other_attr'))]
Run Code Online (Sandbox Code Playgroud)

根据模型的unique_together自动添加.如果我明确地覆盖了这个并且不在字段中包含'user' UniqueTogetherValidator那么一切都像以前一样工作.

这是3.0更新的预期结果吗?在我看来,将request.userperform_create/ perform_update是表现在本教程非常标准的DRF程序.我意识到没有新的验证只是意味着在数据库级别失败,而新的验证可能会提供更好的错误消息,但是

是否有一个解决方案,除了覆盖每个序列化程序的验证,这是一个问题?

在此先感谢您的帮助!

Kev*_*own 7

这是一个已知的问题,我们正在Django REST Framework中进行寻址.截至目前,有在一份报告中关于UniqueTogtherValidator文档,上面写着

注:UniqueTogetherValidation班总是强加它适用的要求总是被所有的成员的隐式约束.具有default值的字段是一个例外,因为它们总是提供一个值,即使从用户输入中省略.

这解释了为什么您看到错误,因为该字段是必需的,即使您是明确设置read_only=True.您可能希望查看CurrentUserDefault课程,这可能适合您的需求,同时避免问题UniqueTogetherValidator.

class ExampleSerializer(serializers.ModelSerializer):
    user = UserSerializer(
        read_only=True
        default=serializers.CurrentUserDefault()
    )

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

应该与你perform_createperform_update钩子做同样的事情.