Django REST ModelViewSet执行PATCH后返回404问题求助
核心问题
错误使用
@action装饰器:你给get_queryset方法添加了@action(detail=True, methods=['patch'])装饰器,这个装饰器是用来定义自定义API端点的,而get_queryset是ModelViewSet的核心方法,负责提供查询集,这种用法会导致你的get_queryset没有覆盖视图的默认逻辑,反而变成了一个无关的API接口(路径为/documents/<pk>/get_queryset/)。详情视图过滤导致对象找不到:当你对
/documents/2/发送PATCH请求时,请求没有携带is_live参数,此时你的get_queryset会返回is_live=True的对象集合,但你要修改的对象此时is_live还是false(你正准备通过这个请求把它改成true),所以对象不在查询集内,最终导致get_object()找不到对象,返回404错误。
修复步骤
1. 移除get_queryset上的错误装饰器
删除@action(detail=True, methods=['patch'])这一行,让get_queryset正确覆盖ModelViewSet的方法。
2. 区分列表与详情视图的查询集逻辑
修改get_queryset,让列表视图按is_live参数过滤,详情视图(更新、查看单个对象等)返回所有对象,确保任何状态的文档都能被修改:
def get_queryset(self): # 获取基础查询集 queryset = super().get_queryset() # 仅对列表视图应用is_live过滤规则 if self.action == 'list': is_live_param = self.request.query_params.get('is_live') if is_live_param is not None: # 处理字符串形式的布尔参数(如'false'转成False) is_live = is_live_param.lower() != 'false' queryset = queryset.filter(is_live=is_live) else: # 默认返回live状态的文档 queryset = queryset.filter(is_live=True) # 详情视图返回所有对象,确保能修改任意状态的文档 return queryset
3. 结合FilterSet简化逻辑(可选)
你已经定义了DocumentFilter,可以利用它简化过滤逻辑,无需手动处理is_live参数:
def get_queryset(self): queryset = super().get_queryset() if self.action == 'list': # 默认返回live文档,有is_live参数时由FilterSet自动处理 if 'is_live' not in self.request.query_params: queryset = queryset.filter(is_live=True) return queryset
4. 移除不必要的update方法修改(可选)
你的update方法强制设置kwargs['partial'] = True,会导致PUT请求也变成部分更新,若不需要这个行为,可以删除该方法,使用ModelViewSet默认的update和partial_update逻辑。
验证效果
- 访问
/documents/?is_live=false可获取所有非live的文档列表 - 对任意文档发送PATCH请求(如
/documents/2/),即使将is_live改为true,也能成功找到对象并完成更新 - 更新后的文档会从
/?is_live=false列表中消失,出现在默认的/documents/列表中
内容的提问来源于stack exchange,提问作者user25455142

