如何在Django中优雅切换数据库配置?
Django启动时优雅切换数据库的方案
问题背景
Django的settings.py中DATABASES字典支持存储多套数据库配置:
# settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }, 'test': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'testing', 'USER': 'bert', 'PASSWORD': '***', 'HOST': 'remotemysql.com', 'PORT': '3306', }, 'dev': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'development', 'USER': 'ernie', 'PASSWORD': '***', 'HOST': 'remotemysql.com', 'PORT': '3306', }, ... }
原本期望通过设置独立变量(如USE_THIS_DB = 'test')快速切换测试、开发、生产数据库,但官方没有直接提供该选项。目前手动修改DATABASES中配置项名称的方式繁琐易出错,且缺乏可移植性。
以下是几种优雅的切换方案:
方案1:环境变量动态指定默认数据库
在settings.py中读取环境变量,动态将目标数据库配置设为default,无需修改代码即可切换:
import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent # 先定义所有数据库的完整配置 DB_CONFIGS = { 'sqlite': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', }, 'test': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'testing', 'USER': 'bert', 'PASSWORD': os.getenv('DB_TEST_PASSWORD'), # 建议密码从环境变量读取,避免硬编码 'HOST': 'remotemysql.com', 'PORT': '3306', }, 'dev': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'development', 'USER': 'ernie', 'PASSWORD': os.getenv('DB_DEV_PASSWORD'), 'HOST': 'remotemysql.com', 'PORT': '3306', }, } # 从环境变量获取要激活的数据库,默认使用sqlite ACTIVE_DB = os.getenv('DJANGO_ACTIVE_DB', 'sqlite') DATABASES = {'default': DB_CONFIGS[ACTIVE_DB]}
启动项目时通过环境变量指定数据库:
# Linux/macOS终端 DJANGO_ACTIVE_DB=test python manage.py runserver # Windows PowerShell $env:DJANGO_ACTIVE_DB='test'; python manage.py runserver
方案2:拆分多Settings文件
将配置按环境拆分,每个环境对应一个独立的settings文件,继承通用配置并指定默认数据库:
在项目的
settings目录下创建以下文件:base.py:存放通用配置(如INSTALLED_APPS、MIDDLEWARE)和所有数据库定义dev.py:开发环境配置test.py:测试环境配置prod.py:生产环境配置
base.py核心内容:
# base.py import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent # 通用配置 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', ... ] # 所有数据库配置 DATABASES = { 'sqlite': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', }, 'test': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'testing', 'USER': 'bert', 'PASSWORD': os.getenv('DB_TEST_PASSWORD'), 'HOST': 'remotemysql.com', 'PORT': '3306', }, 'dev': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'development', 'USER': 'ernie', 'PASSWORD': os.getenv('DB_DEV_PASSWORD'), 'HOST': 'remotemysql.com', 'PORT': '3306', }, }
test.py内容(继承base并切换数据库):
# test.py from .base import * # 设置默认数据库为测试库 DATABASES['default'] = DATABASES['test'] # 添加测试环境专属配置 DEBUG = True ALLOWED_HOSTS = ['localhost']
启动时指定对应settings文件:
python manage.py runserver --settings=myproject.settings.test
方案3:自定义命令行参数(修改manage.py)
如果希望直接通过命令行参数指定数据库,可以修改项目根目录的manage.py,添加自定义参数解析:
#!/usr/bin/env python """Django's command-line utility for administrative tasks.""" import os import sys import argparse def main(): # 解析自定义的--use-db参数 parser = argparse.ArgumentParser() parser.add_argument('--use-db', default='sqlite', choices=['sqlite', 'test', 'dev']) args, remaining_args = parser.parse_known_args() # 将选中的数据库写入环境变量,供settings.py读取 os.environ['DJANGO_ACTIVE_DB'] = args.use_db os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line([sys.argv[0]] + remaining_args) if __name__ == '__main__': main()
启动时直接传递参数:
python manage.py runserver --use-db=test
内容的提问来源于stack exchange,提问作者Darien Marks
相关产品推荐
相关产品推荐

