DRF中serializer.instance调用save()提示无save属性异常如何解决
问题原因
你遇到的response object has no attribute save报错,核心问题出在自定义的get_object(token=token)方法返回值错误:该方法没有按预期返回ORM模型实例,而是返回了DRF的Response对象。当你把这个Response对象传入序列化器构造函数后,object_serializer.instance拿到的就是这个Response实例,Response类本身没有save()方法,调用时自然抛出异常。
绝大多数场景下这个返回值错误是因为写get_object逻辑时,遇到查询不到资源、权限校验不通过的分支,直接return Response(xxx)返回了响应对象,而不是抛出对应异常。
修复方案
- 首先修正
get_object方法逻辑:这个方法的唯一职责是根据传入参数返回匹配的模型实例,任何错误场景直接抛出DRF内置异常即可,不要在方法内返回Response对象。参考写法:
from rest_framework.exceptions import NotFound, PermissionDenied def get_object(self, token): try: # 替换YourModel为你自己的模型类 obj = YourModel.objects.get(token=token) except YourModel.DoesNotExist: # 资源不存在直接抛NotFound,框架会自动转成404响应 raise NotFound("指定token对应的资源不存在") # 权限校验不满足直接抛权限异常,不要返回Response if not obj.user == self.request.user: raise PermissionDenied("你没有操作该资源的权限") return obj
- 修正retrieve方法的逻辑:直接修改模型实例保存后,需要用更新后的实例重新构造序列化器,才能返回最新的字段值;如果需要走序列化器的字段校验规则,推荐用序列化器的partial update逻辑,避免写入不符合规则的字段值。
两种正确的retrieve写法参考:
- 直接修改模型实例的简单写法
def retrieve(self, request, token=None): obj = self.get_object(token=token) obj.update_field = "test field" obj.save() # 用更新后的实例初始化序列化器,保证返回数据是最新值 object_serializer = self.serializer_class(obj) return Response(object_serializer.data)
- 走序列化器校验的规范写法(推荐)
def retrieve(self, request, token=None): obj = self.get_object(token=token) # 传入实例、待更新数据,partial=True表示允许部分字段更新 object_serializer = self.serializer_class( instance=obj, data={"update_field": "test field"}, partial=True ) # 字段校验不通过会自动抛出400响应 object_serializer.is_valid(raise_exception=True) object_serializer.save() return Response(object_serializer.data)
注意事项
DRF视图类中用于查询单条资源的
get_object属于内部调用方法,永远不要在这个方法内直接返回Response、HttpResponse这类响应对象,所有错误分支统一抛出对应异常,由框架的异常处理中间件统一转换为标准格式响应。
内容的提问来源于stack exchange,提问作者fizzbuzzzzz
相关产品推荐
相关产品推荐

