DRF 3.0:UniqueTogetherValidator具有只读字段

时间:2014-12-01 23:36:29

标签: django-rest-framework

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

需要

我有模型(借口错别字,这是简化的,代码工作正常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')

视图集:

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)

串行:

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

    class Meta:
        model = ExampleModel

现在,我不断收到错误说:{"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'))]

根据模型的unique_together自动添加。如果我明确覆盖此内容并且未包含“用户”#39;在UniqueTogetherValidator的字段中,一切都像以前一样。

这是3.0更新的预期后果吗?在我看来,在request.user / perform_create中添加perform_update是非常标准的DRF过程,如教程中所示。我意识到没有新的验证只是意味着在数据库级别失败,而新的验证可能会提供更好的错误消息,但

除了覆盖每个序列化程序的验证之外,还有其他解决方案吗?

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:7)

这是a known issue,我们正在Django REST Framework中进行寻址。截至目前,documentation about UniqueTogtherValidator中有一条说明

的说明
  

注意: UniqueTogetherValidation类总是强加一个隐式约束,它所应用的所有字段始终被视为必需。具有default值的字段是一个例外,因为即使从用户输入中省略它们也总是提供值。

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

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

    class Meta:
        model = ExampleModel

应该与您的perform_createperform_update挂钩做同样的事情。