我们公司的业务系统比较复杂,多个业务系统使用了不同的数据库,有些业务需要跨库访问,并且没有统一的后台管理系统,以应对常规的信息维护。这个场景需要一个能够快递实现增删改查的框架,比如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 北京,上东廓