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

Django使用.update()更新外键字段打印正常但数据库无变更问题

问题根因

你遇到的打印结果符合预期但数据库无变更的核心原因是update操作所在的事务最终被回滚,没有持久化到数据库,另外代码本身也存在逻辑冗余、命名不规范的问题:

  1. 事务未正常提交:Django 中如果开启了请求级事务(ATOMIC_REQUESTS = True)或者手动给视图加了@transaction.atomic装饰器,只要视图执行过程中抛出异常,整个请求内的数据库操作都会被回滚。你在同一个事务会话内执行get查询可以读到未提交的变更,但事务回滚后数据不会写入数据库。如果你的代码是在Django的TestCase测试用例中运行,默认每个用例执行完都会自动回滚事务,也会出现这个现象。
  2. 判断条件逻辑错误:你的if判断中proveedor == ""完全无效,遍历得到的proveedor是EstandarProducto模型实例,永远不可能等于空字符串,这段冗余逻辑虽然不影响执行,但有潜在的逻辑风险。
  3. 变量命名不规范:你将EstandarProducto查询集的遍历变量命名为proveedor,极易和外键字段proveedor混淆,增加代码维护难度。
  4. 低级错误排查:可以确认你查看的数据库和Django配置文件中连接的数据库是否为同一个,避免出现连错库的问题。

解决步骤

1. 事务问题修复

  • 检查视图执行过程中是否抛出未捕获的异常,异常会触发事务回滚;
  • 如果是在测试代码中运行,将TestCase替换为TransactionTestCase即可看到数据库中的实际写入结果,或者在测试代码中手动调用transaction.commit()提交事务。

2. 修正并优化代码

你目前的循环单条更新写法性能极低,完全可以用Django查询集的批量更新能力替代,不需要遍历:

# 直接批量过滤proveedor_id为空的记录,一次性更新
EstandarProducto.objects.filter(
    recinto=id_recinto,
    proveedor_id__isnull=True
).update(proveedor_id=1)

如果需要保留循环逻辑,修正后代码如下:

estandares = EstandarProducto.objects.select_related('recinto','producto','proveedor').prefetch_related(Prefetch('carreras')).filter(recinto=id_recinto)

# 修改变量名避免混淆
for estandar in estandares:
    # 修正判断条件,移除无效的空字符串判断
    if estandar.proveedor_id is None:
        EstandarProducto.objects.filter(id=estandar.id).update(proveedor_id=1)
        x=EstandarProducto.objects.get(id=estandar.id)
        print("ID proveedor : ", x.proveedor.id )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 19:15:04