You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@detail_route时如何更新模型?PATCH请求触发新增而非更新

解决@detail_route(或@action)中PATCH请求创建新条目的问题

嘿,我之前也碰到过一模一样的问题!核心原因是你在自定义的详情路由里没正确绑定要更新的模型实例,导致序列化器默认走了创建逻辑,而非更新逻辑。下面是具体的解决办法:

首先要提一句,DRF 3.10及之后的版本里@detail_route已经被@action装饰器替代了,我用新版写法演示,旧版本只需要把装饰器换回@detail_route(methods=['post', 'patch'])就行。

修改后的完整视图代码

from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
from .models import Company
from .serializers import CompanySerializer
from rest_framework import viewsets

class CompanyViewSet(viewsets.ModelViewSet):
    queryset = Company.objects.all()
    serializer_class = CompanySerializer

    @action(methods=['post', 'patch'], detail=True)
    def custom_company_action(self, request, pk=None):
        # 1. 获取要更新的目标实例(复用ModelViewSet内置方法,自动处理权限、过滤逻辑)
        company_instance = self.get_object()
        
        # 2. 初始化序列化器:必须传入instance参数,同时设置partial=True支持部分更新(PATCH请求的核心)
        serializer = self.get_serializer(
            instance=company_instance,
            data=request.data,
            partial=True
        )
        
        # 3. 验证数据并保存更新
        serializer.is_valid(raise_exception=True)
        serializer.save()
        
        return Response(serializer.data, status=status.HTTP_200_OK)

关键逻辑说明

  • 绑定目标实例:通过self.get_object()获取对应pk的模型实例,传给序列化器的instance参数,这是告诉序列化器要执行更新操作,而不是创建新条目的核心。
  • partial=True参数:这个参数是PATCH请求的必备项,它允许序列化器只处理传入的部分字段,不需要提交所有必填字段。
  • 路由配置:确保装饰器里的detail=True,这样生成的路由会包含模型的pk(比如/companies/{pk}/custom_company_action/),让视图能精准定位到要更新的实例。

如果你的DRF版本低于3.10,只需要把@action替换为@detail_route,其余逻辑完全一致。

内容的提问来源于stack exchange,提问作者lukik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:22:27