使用@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
相关产品推荐
相关产品推荐

