You need to enable JavaScript to run this app. DRF序列化器方法字段在update()方法更新关联模型后仍返回旧值
优惠活动
大模型
产品
解决方案
定价
更多

DRF序列化器方法字段在update()方法更新关联模型后仍返回旧值

问题原因

该问题是Django ORM的关联实例缓存机制导致的:

  • Django会将模型实例的关联查询结果缓存到实例内部,后续访问同一关联时直接读取缓存,不会重新查询数据库。对于OneToOne反向关联(你的Preference与User的关联关系),缓存会存储在shared_user实例的_<related_name>_cache属性中。
  • 你在update()方法中通过Preference.objects.get_or_create()拿到的是独立的Preference实例,修改并保存后,并未同步刷新shared_user实例上已缓存的旧Preference对象。当get_enforce_mfa()通过obj.shared_user.preference访问时,直接读取了缓存的旧实例,因此返回更新前的False。

解决方案

可根据场景选择以下任意一种方案:

方案1:更新Preference后清除关联缓存

在preference.save()之后添加代码,清除shared_user上的preference缓存,确保后续访问时重新查询数据库:

preference.enforce_mfa = enforce_mfa
preference.save()
# 清除shared_user实例上的preference缓存
if hasattr(instance.shared_user, '_preference_cache'):
    del instance.shared_user._preference_cache

也可以直接调用refresh_from_db()刷新整个shared_user实例,自动清除所有关联缓存:

preference.enforce_mfa = enforce_mfa
preference.save()
instance.shared_user.refresh_from_db()

方案2:get_enforce_mfa直接查询最新值

修改get_enforce_mfa方法,直接从数据库查询Preference的最新值,绕过实例关联缓存:

def get_enforce_mfa(self, obj):
    try:
        # 直接查询数据库,不读取实例缓存
        return Preference.objects.get(user=obj.shared_user).enforce_mfa
    except ObjectDoesNotExist:
        return False

方案3:通过关联属性修改Preference

修改update中的更新逻辑,通过shared_user的反向关联获取/创建Preference实例,确保修改的是缓存中的同一个实例:

if self.context['request'].data.get('enforce_mfa'):
    enforce_mfa = json.loads(str(self.context['request'].data.get('enforce_mfa')).lower())
    # 直接通过shared_user的反向关联获取/创建Preference
    try:
        preference = instance.shared_user.preference
    except ObjectDoesNotExist:
        preference = Preference(user=instance.shared_user)
    preference.enforce_mfa = enforce_mfa
    preference.save()

额外优化建议:Meta中设置的depth=1会自动递归序列化所有嵌套关联字段,若不需要深层嵌套的默认序列化,可移除该参数,减少不必要的数据库查询开销。
内容的提问来源于stack exchange,提问作者Anuj TBE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 08:45:04