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

DRF序列化器执行update时to_representation()被两次调用问题排查

问题原因

触发两次to_representation的核心原因是自定义patch方法逻辑和父类UpdateAPIView默认逻辑叠加,导致序列化流程重复执行:

  • 第一次调用:父类partial_update方法完成数据更新后,会自动调用序列化器的to_representation生成响应数据,此时render_stages会将stages从字典列表转换为字符串列表。
  • 第二次调用:你在自定义patch方法中访问response.data,如果继承的ViewMetaMixin或DRF响应处理逻辑再次触发序列化流程,就会将已经处理过的数据结构再次传入render_stages,由于render_stages默认输入的stages是字典列表,尝试读取字符串的name属性就会抛出异常。

同时如果你的render_stages方法是直接修改传入的原始序列化结果字典(而非生成新的副本),会进一步放大这个问题,第一次处理后的异常结构会被第二次调用直接复用。

解决方法

1. 修复render_stages方法的兼容问题

首先修改render_stages,每次处理都生成新的字典副本,避免修改原始数据,同时增加结构判断,只对符合预期的原始结构做处理:

from copy import deepcopy

def render_stages(original_results):
    # 深拷贝原始结果,不修改原对象
    results = deepcopy(original_results)
    # 只有stages是字典列表时才做转换
    if (
        "stages" in results
        and isinstance(results["stages"], list)
        and results["stages"]
        and isinstance(results["stages"][0], dict)
    ):
        stages = results["stages"]
        # 原有转换逻辑
        results["stages"] = [item["name"] for item in stages]
        results["stages_order"] = ",".join([str(item["id"]) for item in stages])
        results["stages_data"] = [{**item, "order": idx + 1} for idx, item in enumerate(stages)]
    return results

2. 优化视图逻辑避免重复序列化

直接重写patch方法的更新逻辑,手动控制序列化流程,只执行一次序列化:

def patch(self, request, *args, **kwargs):
    instance = self.get_object()
    serializer = self.get_serializer(instance, data=request.data, partial=True)
    serializer.is_valid(raise_exception=True)
    self.perform_update(serializer)
    # 仅序列化一次
    return Response({
        "results": serializer.data,
        "messages": [
            {
                "message": _("Settings updated."),
                "message_type": "status",
            }
        ]
    })

修改后不再调用父类的partial_update方法,避免父类自动生成的响应触发多余的序列化流程。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 07:54:04