我们公司的业务系统比较复杂,多个业务系统使用了不同的数据库,有些业务需要跨库访问,并且没有统一的后台管理系统,以应对常规的信息维护。这个场景需要一个能够快递实现增删改查的框架,比如django,配合强大的admin能力,快速的搭建出可用的系统。碰到的第一个问题就是管理多数据库。
在django文档中,使用DATABASE_ROUTERS配置,支持多数据库链接,以下是我项目中用到的代码:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb',
'HOST': '192.168.0.2',
'PORT': 3306,
'USER': 'myuser1',
'PASSWORD': 'mypassword1',
},
'mydb1': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb1',
'HOST': '192.168.0.3',
'PORT': 3306,
'USER': 'myuser1',
'PASSWORD': 'mypassword1',
},
'mydb2': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb2',
'HOST': '192.168.0.3',
'PORT': 3306,
'USER': 'myuser1',
'PASSWORD': 'mypassword1',
},
}
settngs.py文件中,DATABASES段定义多个数据库
在我的项目目录下创建文件 auth_router.py,其中定义类AuthRouter; 另一个文件 apps_router.py中定义类AppsRouter。其中auth_router.py是为了让django的基础app都访问默认库 default
目录结构如下:
myapp
myapp
__init__.py
settings.py
auth_router.py
apps_router.py
接下来,在settings.py中定义DATABASE_ROUTERS和DATABASE_APPS_MAPPING
DATABASE_ROUTERS = ['myapp.auth_router.AuthRouter', 'myapp.apps_router.AppsRouter']
DATABASE_APPS_MAPPING = {
'myapp1': 'mydb1',
'myapp2': 'mydb2',
...
}
最后,在每个应用(myapp1, myapp2)的 models.py中定义Model时,使用app_label属性定义为所属的app。
class MyModel(models.Model):
...
class Meta:
app_label = 'myapp1'
程序运行的时候,会根据Model的app_label属性找到对应的app,从DATABASE_APPS_MAPPING中找到app对应的数据库配置,使用该数据库配置读取数据。
从django的文档中可以发现,使用DATABASE_ROUTER还可以配置读写分离的数据源,本例中没有涉及到。
附1 auth_router.py
class AuthRouter:
"""
A router to control all database operations on models in the
auth and contenttypes applications.
"""
route_app_labels = {'admin', 'auth', 'contenttypes', 'sessions', 'logentrys'}
def db_for_read(self, model, **hints):
"""
Attempts to read auth and contenttypes models go to auth_db.
"""
if model._meta.app_label in self.route_app_labels:
return 'default'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write auth and contenttypes models go to auth_db.
"""
if model._meta.app_label in self.route_app_labels:
return 'default'
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the auth or contenttypes apps is
involved.
"""
if (
obj1._meta.app_label in self.route_app_labels or
obj2._meta.app_label in self.route_app_labels
):
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure the auth and contenttypes apps only appear in the
'auth_db' database.
"""
if app_label in self.route_app_labels:
return db == 'default'
return None
附2 apps_router.py
from django.conf import settings
DATABASE_MAPPING = settings.DATABASE_APPS_MAPPING
class AppsRouter(object):
"""
A router to control all database operations on models for different
databases.
In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
will fallback to the `default` database.
Settings example:
DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
"""
def db_for_read(self, model, **hints):
"""Point all read operations to the specific database."""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None
def db_for_write(self, model, **hints):
"""Point all write operations to the specific database."""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None
def allow_relation(self, obj1, obj2, **hints):
"""Allow any relation between apps that use the same database."""
db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
if db_obj1 and db_obj2:
# 20221015,如果前三位相同,也允许连接
if db_obj1 == db_obj2 or db_obj1[:3] == db_obj2[:3]:
return True
else:
return False
return None
def allow_migrate(self, db, app_label, model=None, **hints):
"""
All non-auth models end up in this pool.
"""
if DATABASE_MAPPING.get(app_label) == db:
return True
elif app_label in DATABASE_MAPPING:
return False
return None
参考链接: https://docs.djangoproject.com/zh-hans/5.2/topics/db/multi-db/#topics-db-multi-db-routing
2025/9/3 北京,上东廓