在Heroku上共享数据库的Django应用:一次性配置'shared'数据库
在Heroku上为多个Django应用共享数据库的优化方案
我来帮你解决这两个关于Django多应用共享Heroku数据库的问题,这在多服务共享数据的场景里很常见:
1. 一次性配置默认数据库,避免重复写using('shared')
你完全不需要在每段ORM代码里加环境判断和using('shared'),直接在settings.py里动态切换默认数据库就可以搞定。思路是:本地开发时用你原来的default数据库,部署到Heroku(非DEBUG环境)时,把默认数据库替换为那个共享的shared数据库。
具体配置代码如下:
# settings.py import os import dj_database_url BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DEBUG = os.environ.get('DEBUG', 'False') == 'True' # 本地开发数据库配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }, # Heroku共享数据库,直接用dj_database_url读取环境变量 'shared': dj_database_url.config(conn_max_age=600, ssl_require=True) } # 非DEBUG环境下,将默认数据库切换为共享库 if not DEBUG: DATABASES['default'] = DATABASES['shared']
这样修改后,你的业务代码里完全不用再管环境判断,直接写User.objects.all()就可以了——本地开发时用本地数据库,部署到Heroku后自动用共享数据库,彻底摆脱重复的using('shared')代码。
你之前设想的修改User模型对象的方式其实不太合适,因为这会破坏模型类的原有结构,而修改settings.py是更优雅、更符合Django设计的方案。
2. 为外键指定共享数据库中的模型
跨数据库关联模型时,Django不能直接引用其他数据库的模型(因为默认ORM操作只针对当前默认数据库),我们需要在当前应用中定义一个**非托管模型(Unmanaged Model)**来映射共享数据库里的User表,然后用这个非托管模型作为外键的目标。
具体实现步骤:
- 定义一个和共享数据库中
User表结构匹配的非托管模型(至少包含外键需要的主键字段,以及你需要用到的其他字段) - 在你的
Article模型中,将外键指向这个非托管模型
示例代码:
# 当前应用的models.py from django.db import models # 映射共享数据库中的account_user表(原User模型的表名默认是account_user) class SharedUser(models.Model): id = models.IntegerField(primary_key=True) username = models.CharField(max_length=150) email = models.EmailField(blank=True) # 这里可以添加你需要用到的其他User表字段 class Meta: managed = False # 告诉Django不要为这个模型创建/运行迁移 db_table = 'account_user' # 必须和共享数据库中User表的实际名称一致 app_label = 'account' # 对应原User模型所属的app # 定义Article模型,关联SharedUser class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() # 关联共享数据库的User,注意关闭数据库约束(跨库外键约束多数数据库不支持) author = models.ForeignKey(SharedUser, on_delete=models.DO_NOTHING, db_constraint=False) created_at = models.DateTimeField(auto_now_add=True)
这里有几个关键注意点:
managed=False:必须设置,因为这个表已经在共享数据库中存在,当前应用不需要管理它的生命周期db_table:必须和原User模型在数据库中的实际表名一致(Django默认表名是appname_modelname,所以这里是account_user)db_constraint=False:由于跨数据库的外键约束在PostgreSQL(Heroku默认用的数据库)中不被支持,所以要关闭这个选项,避免迁移时出错on_delete:Django要求外键必须指定这个参数,根据你的业务需求选择合适的行为(比如DO_NOTHING、SET_NULL等)
如果你的场景更复杂(比如多个模型需要跨库关联),也可以考虑使用Django的**数据库路由(Database Router)**来统一管理模型的数据库路由,但对于这种单共享库的场景,用非托管模型已经足够简单高效了。
内容的提问来源于stack exchange,提问作者Randy Tang
相关产品推荐
相关产品推荐

