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

调用Serializer.create方法出现意外行为,致无关数据丢失(DRF)

问题原因及解决办法

环境依赖

Django>=4.2.7,<4.3.0
djangorestframework>=3.14.0,<3.15.0
python-dateutil>=2.8.2,<2.9.0
psycopg2-binary>=2.9.9,<3.0.0
django-crontab>=0.7.1,<0.8.0

问题分析

核心原因是Python可变对象的引用传递特性:字典属于可变类型,当你把user_data存入data字典并传入serializer.create后,User.objects.create(或其内部调用的CostumUserCreate方法)对user_data执行了原地修改操作(比如用pop()删除键、clear()清空字典),导致外部的原user_data字典同步被改变——因为它们指向内存中的同一个对象。而profile_data未被做类似修改,所以保持正常。

从代码逻辑看,虽然serializer.create只是获取数据并传递,但User.objects.create内部大概率对user_data做了原地清理操作(比如处理密码时移除password键),才会引发这个问题。

解决办法

方法1:在Serializer的create方法中使用字典副本

修改create方法,对获取到的user_data创建副本,避免原对象被修改:

def create(self, validated_data):
    """
    Passing in the restructured validated_data to the
    CostumUserCreate method.
    """
    # 创建副本,隔离原字典与内部操作
    user_data = validated_data.get('user_data').copy()
    profile_data = validated_data.get('profile_data')

    new_user = User.objects.create(
        user_data=user_data,
        profile_data=profile_data
    )

    return new_user

方法2:修正User模型的创建逻辑

如果User.objects.create(或CostumUserCreate)内部存在对user_data的原地修改,比如:

# 假设User模型create方法中有类似代码
def create(self, user_data, profile_data):
    password = user_data.pop('password')  # 原地移除password键
    # 其他业务逻辑

将其改为操作副本:

def create(self, user_data, profile_data):
    # 创建副本后再操作,不影响原字典
    user_data_copy = user_data.copy()
    password = user_data_copy.pop('password')
    # 后续逻辑使用user_data_copy而非原user_data

方法3:测试代码中传入副本(临时方案)

如果只是测试阶段临时规避,可以在组装data时传入user_data的副本:

data['user_data'] = user_data.copy()  # 传入副本,原字典不受内部操作影响

验证修改

完成上述任意一种修改后,重新运行测试,外部的user_data字典将保持初始状态,不会被清空。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 23:19:59