Django多数据库配置与分库读写分离实战指南

Elena
Elena
发布时间:2026-10-12| 3人浏览过
原创

本文详解Django中多数据库的配置与路由机制,涵盖垂直与水平分库方案。通过自定义DatabaseRouter实现读写分离及一主多从架构,并对比自动路由与手动路由的性能差异,提供查询、保存及删除操作的具体代码示例,帮助开发者在小规模项目中高效管理多数据库环境。

定义及路由机制

定义

在Django项目的settings配置文件中,DATABASES是一个字典结构,用于定义项目所需的所有数据库连接信息。例如,以下配置示例中定义了两个独立的数据库实例。

DATABASES = {
 'default': {
 'NAME': 'app_data',
 'ENGINE': 'django.db.backends.postgresql_psycopg2',
 'USER': 'postgres_user',
 'PASSWORD': 's3krit'
 },
 'user1': {
 'NAME': 'user1_data',
 'ENGINE': 'django.db.backends.mysql',
 'USER': 'mysql_user',
 'PASSWORD': 'priv4te'
 }
 'user2': {
 'NAME': 'user2_data',
 'ENGINE': 'django.db.backends.mysql',
 'USER': 'mysql_user',
 'PASSWORD': 'priv4te'
 }
} 

那么在实际运行中,Django何时调用default数据库,何时调用user1数据库呢?这取决于后续配置的路由规则。

路由注册

class User1Router(object):
 """
 A router to control all database operations on models in the
 auth application.
 """
 def db_for_read(self, model, **hints):
 """
 Attempts to read auth models go to auth_db.
 """
 if model._meta.app_label == 'auth':
  return 'user1'
 return None

 def db_for_write(self, model, **hints):
 """
 Attempts to write auth models go to auth_db.
 """
 if model._meta.app_label == 'auth':
  return 'user1'
 return None

 def allow_relation(self, obj1, obj2, **hints):
 """
 Allow relations if a model in the auth app is involved.
 """
 if obj1._meta.app_label == 'auth' or \
  obj2._meta.app_label == 'auth':
  return True
 return None

 def allow_syncdb(self, db, model):
 """
 Make sure the auth app only appears in the 'auth_db'
 database.
 """
 if db == 'auth_db':
  return model._meta.app_label == 'auth'
 elif model._meta.app_label == 'user1':
  return False
 return None

class User2Router(object):
 """
 A router to control all database operations on models in the
 auth application.
 """
 def db_for_read(self, model, **hints):
 """
 Attempts to read auth models go to auth_db.
 """
 if model._meta.app_label == 'auth2':
  return 'user2'
 return None

 def db_for_write(self, model, **hints):
 """
 Attempts to write auth models go to auth_db.
 """
 if model._meta.app_label == 'auth2':
  return 'user2'
 return None

 def allow_relation(self, obj1, obj2, **hints):
 """
 Allow relations if a model in the auth app is involved.
 """
 if obj1._meta.app_label == 'auth' or \
  obj2._meta.app_label == 'auth':
  return True
 return None

 def allow_syncdb(self, db, model):
 """
 Make sure the auth app only appears in the 'auth_db'
 database.
 """
 if db == 'auth_db':
  return model._meta.app_label == 'auth2'
 elif model._meta.app_label == 'user2':
  return False
 return None

User1Router的路由逻辑设定为:当模型所属的app_label为auth时,数据读写操作指向user1数据库;其他情况则遵循默认或其他路由规则。User2Router的逻辑与此类似,用于处理不同的业务模块。

如何注册路由

仅定义路由类无法生效,必须将其注册到Django框架中。具体操作是在settings.py文件中添加DATABASE_ROUTERS配置项。

DATABASE_ROUTERS = ['path.to.User1Router' , 'path.to.User2Router']

其中path.to表示User1Router类的完整Python包路径。因此,User1Router类无需必须定义在settings.py中,可以放置在项目任意可用的模块目录下。

路由机制

Django内部是如何选择具体路由器的呢?其核心机制如下:

1. Django会按照DATABASE_ROUTERS列表中注册的顺序,依次轮询每个路由器。首先检查User1Router是否返回非空字符串(即具体的数据库名称)。如果返回了非空值,则直接使用该数据库;如果返回None,则继续检查下一个路由器。

2. 接着验证User2Router,若其返回非空字符串,则使用该数据库;若仍返回None,则最终回退到default数据库。

3. 由此可见,路由器的注册顺序直接影响结果。注册在列表前面的路由器具有更高的优先级,会被优先匹配和使用。

自动路由和手动路由

上述通过DATABASE_ROBERS配置的路由方式称为自动路由。其含义是Django会在每次数据库操作时自动轮询已注册的路由器列表,根据模型属性自动决定数据存储在哪个数据库,开发者在业务代码中无需显式指定。

手动路由则允许开发者在代码中显式指定某个Model实例应保存或读取自哪个数据库。

此外,手动路由在性能上具有一定优势。若定义了多个数据库且使用自动路由,每次保存或读取Model时都需要遍历整个路由列表,效率较低。如果程序逻辑清晰,明确知道当前代码应连接哪个数据库,显式指定方式能避免轮询开销,效率更高。

手动路由

查询

在执行查询时,使用QuerySet的using()方法,参数指定目标数据库名称。

User.objects.using('user1').all()

保存或者更新

在调用Model的save()方法时,传入using参数,值为目标数据库名称。

>>> my_object.save(using='user1')

删除

在调用Model的delete()方法时,同样传入using参数指定目标数据库。

>>> user_obj.delete(using='user1')

分库技术

下面简要介绍两种常见的分库思路。

垂直分库

垂直分库的核心思想是一个App对应一个独立的数据库。上述自动路由的例子即为垂直分库的典型场景:auth1模块的数据存入user1数据库,auth2模块的数据存入user2数据库。当然,垂直分库也可以结合手动路由来实现。

水平分库

对于水平分库,建议采用手动路由。因为不同Model的分库规则可能各异,使用自动路由实现复杂且可能影响性能。而手动路由允许每个Model根据自定义规则灵活选择数据库,更加高效。

补充知识:Django实现数据库读写分离、一主多从、分库

读写分离

在工程实践中,MySQL读写分离是常见需求。在Django中实现读写分离只需几步简单配置。

首先,配置读库和写库的连接信息。

在django项目的settings.py文件中,分别配置主库(写库)和从库(读库)的连接参数。

DATABASES = {
 'default': {
 'ENGINE': 'django.db.backends.mysql', 
 'NAME': 'WIPS',   
 'USER': 'mysql',   
 'PASSWORD': '360tianxun#^)Sec',   
 'HOST': '',   
 'PORT': '',   
 },
 'slave': {
 'ENGINE': 'django.db.backends.mysql',
 'NAME': 'TEST',   
 'USER': 'mysql',   
 'PASSWORD': '360tianxun#^)Sec',   
 'HOST': '',   
 'PORT': '',   
 },
}

接下来,需要创建数据库的路由分发类。

可以在appname/utils目录下创建一个db_router.py文件,并在其中定义DBRouter类。在该类中实现db_for_read和db_for_write方法,以区分读库和写库的选择逻辑。

class DBRouter(object):
 def db_for_read(self, model, **hints):
 return "slave"
 
 def db_for_write(self, model, **hints):
 return "default"
 
 def allow_relation(self, obj1, obj2, **hints):
 return True

最后,在settings.py中添加路由配置,将自定义的路由器类注册到系统中。

DATABASE_ROUTERS = ['appname.utils.db_router.DBRouter' ]

完成上述配置后,重启Django服务即可生效。

这里需要注意的是,Django仅负责应用层面的读写分离逻辑,MySQL主库与从库之间的数据同步操作仍由MySQL自身机制负责,Django不介入此过程。

一主多从

一主多从方案在实际应用中更为常见。在读写分离配置的基础上,只需修改少量代码即可实现一主多从架构。

首先,修改settings.py,增加所有从库的连接配置。

其次,修改db_router类中的db_for_read()方法。以下示例展示了随机选取读库的逻辑,实际应用中也可根据负载情况选择其他调度算法。

class DBRouter(object):
 def db_for_read(self, model, **hints):
 import random
 return random.choice(['slave', 'slave2', 'slave3'])

分库

当需要不同App使用不同数据库时,可以利用Model中的app_label属性来实现数据库路由。

class DBRouter(object):
 def db_for_read(self, model, **hints):
 if model._meta.app_label == 'app01':
  import random
  return random.choice(['app01_slave1', 'app01_slave2', 'app01_slave3'])
 if model._meta.app_label == 'app02':
  return "app02_slave"

按照上述步骤,即可轻松实现MySQL的读写分离、一主多从以及分库功能。但需注意,该方法仅建议用于小规模项目,大型项目需考虑更复杂的分布式方案。

以上这篇django 多数据库及分库实现方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。