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

Django中指定.save(using='default')仍指向其他数据库的问题

Django save(using='default') still tries to access 'other' database table

我将Django settings.py配置如下:

DATABASES = {
    'default': {
        # 省略若干配置
        'NAME': 'myproject',
        'HOST': 'localhost',
    },
    'other': {
        'NAME': 'other',
        'HOST': 'else.where',
    }
}

我想要从other数据库获取数据并保存到default数据库,操作代码如下:

things = Thing.objects.using('other').raw('SELECT code,created FROM other.otherapp_bigthing WHERE created>...')
# 'code'是other库中的唯一字符串,也是Thing模型的主键
for t in things:
    t.save(using='default')

执行后出现ProgrammingError: (1146, "Table 'other.myapp_thing' doesn't exist")错误,该错误本身符合实际情况,但根据using参数的文档说明,我预期记录会保存到myproject.myapp_thing。为何明确指定使用default时,数据库名称仍取自other的配置?

这个问题的核心在于通过raw()查询返回的Model实例会绑定到你指定的源数据库别名,即使你在save()时指定了不同的using参数,Django仍会优先使用实例本身的_state.db属性来确定操作的数据库。

为什么会这样?

当你执行Thing.objects.using('other').raw(...)时,返回的RawQuerySet中的每个Thing实例,其内部的_state.db属性会被设置为'other'——这是Django用来跟踪实例所属数据库的标记。

当你调用t.save(using='default')时,由于实例已经有了主键值(code),Django默认会尝试执行UPDATE操作,而在生成UPDATE语句时,它会优先使用实例_state.db中存储的数据库别名(也就是'other'),而不是你传入的using参数。这就导致它去other数据库中查找Thing模型对应的myapp_thing表,而该表只存在于default库中,所以抛出了表不存在的错误。

解决方案

有两种简单的方式可以解决这个问题:

1. 创建新的Thing实例(推荐)

不要直接保存从raw()查询得到的实例,而是用查询到的数据创建一个全新的Thing对象,再保存到default数据库:

things = Thing.objects.using('other').raw('SELECT code,created FROM other.otherapp_bigthing WHERE created>...')
for t in things:
    # 基于查询到的数据创建新实例
    new_thing = Thing(code=t.code, created=t.created)
    new_thing.save(using='default')

这种方式最清晰,避免了实例绑定到源数据库的问题,新实例默认会使用default数据库(或者你明确指定using)。

2. 修改实例的_state.db并强制插入

如果你想复用原实例,可以修改它的_state.db属性,同时使用force_insert=True强制Django执行INSERT操作(而不是UPDATE):

things = Thing.objects.using('other').raw('SELECT code,created FROM other.otherapp_bigthing WHERE created>...')
for t in things:
    # 将实例绑定到default数据库
    t._state.db = 'default'
    # 强制插入,避免Django尝试UPDATE操作
    t.save(force_insert=True)

force_insert=True会告诉Django忽略实例的现有主键状态,直接执行INSERT,确保数据写入default库的myapp_thing表。

内容的提问来源于stack exchange,提问作者arne.b

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:11:23