簡體   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