部分更新数据库通过补丁,Django REST框架。

huangapple go评论76阅读模式
英文:

Update database partially by patch, django rest framework

问题

Here is the translated code portion:

我有我的 `CustomUser` 模型它扩展了 `AbstractUser`

```python
class CustomUser(AbstractUser):
    detail = models.JSONField(default=dict)
    created_at = models.DateTimeField(auto_now_add=True)    
    updated_at = models.DateTimeField(auto_now=True)

然后,现在我只想更新 detail 列。

在 JavaScript 中,通过以下方式进行补丁请求。

var formData = new FormData();
var status = {
    fileObj:this.fileObj.id
}
console.log("syncdata to user table",status);
console.log("syncdata for user:",request);
formData.append("detail",JSON.stringify(status));
axios.patch(
    `/api/customusers/3/`,formData,{
    }
).then(function (response) {
    console.log("syncdata customuser is saved:",response); 
})
.catch(function (response) {
    console.log("syncdata customuser failed:",response);
});

这将通过 <QueryDict: {'detail': ['{"fileObj":19}']}> 作为 request.data

views.py 中:

class CustomUserViewSet(viewsets.ModelViewSet):
    serializer_class = s.CustomUserSerializer   
    queryset = m.CustomUser.objects.all()

    def update(self,request,*args,**kwargs):
        print("custom user update")
        print(request.data) // <QueryDict: {'detail': ['{"fileObj":19}']}>
        instance = self.get_object()
        serializer = self.get_serializer(instance,data = request.data)
        if serializer.is_valid():
            self.perform_update(serializer)
            return Response(serializer.data)
        else:
            print(serializer.errors) // check error.

然而,serializer 返回错误:

{'username': [ErrorDetail(string='This field is required.', code='required')]}

我想要做的只是更新 detail 字段,但它要求 username。我错在哪里?


<details>
<summary>英文:</summary>

I have my `CustomUser` model which extend `AbstractUser`

    class CustomUser(AbstractUser):
        detail = models.JSONField(default=dict)
        created_at = models.DateTimeField(auto_now_add=True)    
        updated_at = models.DateTimeField(auto_now=True)  
        pass

then now I want to update only `detail` column.

in javascript through patch request like this below.

     var formData = new FormData();
     var status = {
         fileObj:this.fileObj.id
     }
     console.log(&quot;syncdata to user table&quot;,status);
     console.log(&quot;syncdata for user:&quot;,request);
     formData.append(&quot;detail&quot;,JSON.stringify(status));
     axios.patch(
         `/api/customusers/3/`,formData,{
         }
     ).then(function (response) {
         console.log(&quot;syncdata customuser is saved:&quot;,response); 
     })
     .catch(function (response) {
         console.log(&quot;syncdata customuser failed:&quot;,response);
     });

this through `&lt;QueryDict: {&#39;detail&#39;: [&#39;{&quot;fileObj&quot;:19}&#39;]}&gt;` as `request.data`

in views.py

    class CustomUserViewSet(viewsets.ModelViewSet):
        serializer_class = s.CustomUserSerializer   
        queryset = m.CustomUser.objects.all()
    
        def update(self,request,*args,**kwargs):
            print(&quot;custom user update&quot;)
            print(request.data) // &lt;QueryDict: {&#39;detail&#39;: [&#39;{&quot;fileObj&quot;:19}&#39;]}&gt;
            instance = self.get_object()
            serializer = self.get_serializer(instance,data = request.data)
            if serializer.is_valid():
                self.perform_update(serializer)
                return Response(serializer.data)
            else:
                print(serializer.errors) // check error.


However `serializer` returns the error, 

    {&#39;username&#39;: [ErrorDetail(string=&#39;This field is required.&#39;, code=&#39;required&#39;)]}

What I want to do is just update the `detail` field only, but it require the `username`.

Where am I wrong?



</details>


# 答案1
**得分**: 1

```python
这是实现在ModelViewSet中进行更新和部分更新的Mixin类。

在接收到HTTP `PATCH` 方法请求时,DRF会调用你的 `partial_update` 方法。然后在 `update` 方法中,`serializer = self.get_serializer(instance, data=request.data, partial=partial)` 通过 `partial` 参数来判断是否进行部分更新。所以要解决你的问题,你只需要重新编写你的 `update` 方法如下:

```python
def update(self, request, *args, **kwargs):
    partial = kwargs.pop('partial', False)
    print("自定义用户更新")
    print(request.data)  # <QueryDict: {'detail': ['{"fileObj":19}']}>
    instance = self.get_object()
    serializer = self.get_serializer(instance, data=request.data, partial=partial)
    if serializer.is_valid():
        self.perform_update(serializer)
        return Response(serializer.data)
    else:
        print(serializer.errors)  # 检查错误

<details>
<summary>英文:</summary>

This is the Mixin class that implements update and partial update in ModelViewSet.
```python
class UpdateModelMixin:
    &quot;&quot;&quot;
    Update a model instance.
    &quot;&quot;&quot;
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop(&#39;partial&#39;, False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, &#39;_prefetched_objects_cache&#39;, None):
            # If &#39;prefetch_related&#39; has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs[&#39;partial&#39;] = True
        return self.update(request, *args, **kwargs)

When receiving HTTP PATCH method request, DRF will call your partial_update method.Then the serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer in the update method judges whether it is a partial update through the partial parameter. So to solve your problem, you just need to rewrite your update method as:

def update(self,request,*args,**kwargs):
    partial = kwargs.pop(&#39;partial&#39;, False)
    print(&quot;custom user update&quot;)
    print(request.data) // &lt;QueryDict: {&#39;detail&#39;: [&#39;{&quot;fileObj&quot;:19}&#39;]}&gt;
    instance = self.get_object()
    serializer = self.get_serializer(instance,data = request.data, partial=partial)
    if serializer.is_valid():
        self.perform_update(serializer)
        return Response(serializer.data)
    else:
        print(serializer.errors) // check error.

huangapple
  • 本文由 发表于 2023年5月18日 11:06:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76277473.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定