繁体   English   中英

Django Rest Framework (DRF) 拒绝在更新 (PUT) 请求中使用外键验证数据

[英]Django Rest Framework (DRF) Refuses to Validate Data with Foreign Keys in Update (PUT) Request

使用 Django REST Framework (DRF),我试图遵循此链接提供的嵌套序列化程序的 DRF 文档。 目前,让我们假设我的代码如下所示:

模型.py

class PvlEntry(models.Model):

    pvl_project = models.OneToOneField("review.ProjectList", on_delete=models.CASCADE, related_name='pvl_project')
    pvl_reviewer = models.ForeignKey('auth.User', on_delete=models.CASCADE, related_name='+')
    pvl_worktype_is_correct = models.BooleanField(blank=False, null=False)
    pvl_hw_description = models.TextField(blank=False, null=False)

class ProjectList(models.Model):
    """ 
    """
    project_number = models.IntegerField(blank=False, null=False, unique=True)
    project_manager = models.CharField(blank=False, max_length=255, null=False)
    project_name = models.CharField(blank=False,
                                          max_length=255,
                                          null=False)
    project_description = models.CharField(blank=True,
                                         max_length=1024,
                                         null=True)

视图.py

class PvlEntryListCreateAPIView(ListCreateAPIView):
    """ This view is leveraged for jsGrid so that we can have jsGrid produce
        a JavaScript enabled view for actions like editing and filtering of
        the project vetting list.
    """
    queryset = PvlEntry.objects.all()
    serializer_class = PvlEntrySerializer
    name = 'listcreate-pvlentry'

    def get_queryset(self):
        qs = self.queryset.all()

        return qs

class PvlEntryRetrieveUpdateDestroyAPIView(RetrieveUpdateDestroyAPIView):
    """ Leveraged for jsGrid
    """
    queryset = PvlEntry.objects.all()
    serializer_class = PvlEntrySerializer
    name = 'rud-pvlentry'

序列化程序.py

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = [
            'id',
            'first_name',
            'last_name',
            'email'
        ]

class ProjectListSerializer(serializers.ModelSerializer):

    class Meta:
        model = ProjectList
        fields = '__all__'

class PvlEntrySerializer(serializers.ModelSerializer):

    pvl_project = ProjectListSerializer()
    pvl_reviewer = UserSerializer()
   
    def update(self, instance, validated_data):
        print(validated_data)
        return super(PvlEntrySerializer, self).update(self, instance, validated_data)

    class Meta:
        model = PvlEntry
        fields = '__all__'

现在,我明白,由于这段代码现在位于,它不是一个可写的序列化程序。 但是,有了上面的代码,我不应该至少通过序列化程序对数据的验证吗?

使用 DRF 可浏览 API,当我尝试使用 RetriveUpdateDestroy 内置 API 视图的 PUT 操作时,我收到类似于以下内容的错误:

PUT /pvl/grid/11    
HTTP 400 Bad Request
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "pvl_project": {
        "project_number": [
            "pvl entry with this project number already exists."
        ]
    }
}

同样,我明白我不能像现在这样使用代码执行更新 (PUT),但它至少不应该通过序列化/验证阶段吗? 我也不会创建新记录。 我只是尝试执行更新。 那么,为什么要验证“具有此项目编号的 pvl 条目”是否已经存在?

stackoverflow 上有很多帖子涉及或围绕这个问题跳舞,但由于某种原因,我无法依靠其中任何一个来解决问题。

我也尝试返回并用PrimaryKeyRelatedFields替换嵌套的序列化程序,但该方法不返回相关数据,只返回对相关数据的引用。

我还尝试了单独的序列化程序,但这种方法对我实现的用于使用模板中的数据的 jsGrid JavaScript 效果不佳。

肯定有一个简单的解决方案吗?

第一个解决方案是您可以使用PATCH方法而不是PUT并且不要在表单/ajax 数据中发送pvl_project (记住设置所需的属性,如pvl_project = ProjectListSerializer(required=False)

问题是在 drf PUT请求方法中尝试将给定实例中的所有提供的数据替换为一个 - 这意味着它将首先分析没有PvlEntry.pvl_project属性重复,因为它的OneToOneField

另一方面, PATCH可以partialy更新数据(你可以分析这个问题),你甚至不关心required=False序列化器属性,因为它只会更新请求中提供的数据(如何通过PUT方法更新部分在我的最后一个注释)。

第二

现在,当我们解决了第一个概念时,我们可以继续让这个序列化程序工作。 假设您在每个模型上设置了uuid属性(使用id字段不是最佳实践),并且您希望通过给定的uuid属性值设置pvl_project

您可以覆盖ProjectListSerializer中的to_internal_value方法,该方法用于保存实例并通过给定数据简单地搜索给定对象。

class ProjectListSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProjectList
        fields = '__all__'
    
    def to_internal_value(self, data):
        # you can validate data here for sure that provided data is correct uuid string
        try:
            return ProjectList.objects.get(uuid=data)
        except ProjectList.DoesNotExist:
            raise ValidationError(['Project list with the given uuid does not exist'])

这个序列化器现在就像一个很好的弹性切换 json <-> api <-> django 模型实例世界。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM