django 多数据库及分库实现方式


Posted in Python onApril 01, 2020

定义及路由机制

定义

在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'
 }
}

那么什么时候调用default什么时候调用users数据库呢,这就需要下面的路由。

路由注册

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的路由逻辑是,如果model所属的app是auth的话,就使用user1数据库,否则就使用其他的;User2Router的逻辑类似。

如何注册路由

光定义路由程序无法调用到,还需要注册到django中,在settings中定义

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

path.to:是User1Router的完整python包路径,所以,User1Router不一定要在settings中实现,可以在任何地方。

路由机制

那么django是如何选择其中一个路由的呢?

1. django按照注册的顺序轮询DATABASE_ROUTERS,所以首先验证User1Router是否返回了非空字符串,如果是,则使用User1Router;如果不是则接着验证后面的Router;

2. 同样验证User2Router,如果User2Router返回了非空字符串,则使用User2Router;如果不是则使用default数据库;

3. 所以可以看出,路由注册的顺序是会影响最后的结果的,注册在前面的路由会优先被使用;

自动路由和手动路由

上面定义的Router是自动路由,意思是django会自动轮询所注册的路由器,某个model会保存在哪个数据库,是django通过注册的Router自动获得的,在编码中你不需要指定;

手动路由,则是你可以在编码中指定某个model要保存到哪个数据库。

而且手动路由也有性能方面的优点,如果定义了很多个数据库,每次保存或者读取model都要把轮询一遍路由列表,显然效率有些低,如果程序逻辑清楚的知道当前的代码应该连接哪个数据库,显示指定的方式显然效率更高。

手动路由

查询

使用using函数,参数就是要查询的数据库

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

保存或者更新

使用save的using参数,值就是要使用的数据库

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

删除

使用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文件,在文件中定义db_router类。类中实现读库写库的选择。

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主库、从库的同步操作并不归django负责,依然需要mysql实现。

一主多从

一主多从的方案在实际应用中是更常见的配置。在上面配置的基础上,只需要修改几个地方,就可以实现一主多从了。

首先,修改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来实现db的路由。

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 相关文章推荐
利用Python画ROC曲线和AUC值计算
Sep 19 Python
HTML中使用python屏蔽一些基本功能的方法
Jul 07 Python
Python利用turtle库绘制彩虹代码示例
Dec 20 Python
Python实现按中文排序的方法示例
Apr 25 Python
Python3.遍历某文件夹提取特定文件名的实例
Apr 26 Python
Python判断字符串是否为字母或者数字(浮点数)的多种方法
Aug 03 Python
Python3实现的回文数判断及罗马数字转整数算法示例
Mar 27 Python
Python Web程序搭建简单的Web服务器
Jul 31 Python
Python3 A*寻路算法实现方式
Dec 24 Python
Python开发企业微信机器人每天定时发消息实例
Mar 17 Python
从0到1使用python开发一个半自动答题小程序的实现
May 12 Python
Python命令行参数argv和argparse该如何使用
Feb 08 Python
详解使用python3.7配置开发钉钉群自定义机器人(2020年新版攻略)
Apr 01 #Python
Django更新models数据库结构步骤
Apr 01 #Python
pycharm工具连接mysql数据库失败问题
Apr 01 #Python
利用Python自动化操作AutoCAD的实现
Apr 01 #Python
python使用信号量动态更新配置文件的操作
Apr 01 #Python
python和pywin32实现窗口查找、遍历和点击的示例代码
Apr 01 #Python
python自动脚本的pyautogui入门学习
Apr 01 #Python
You might like
PHP和javascript常用正则表达式及用法实例
2014/07/01 PHP
Js 获取HTML DOM节点元素的方法小结
2009/04/24 Javascript
基于JQuery实现鼠标点击文本框显示隐藏提示文本
2012/02/23 Javascript
jquery ajax跨域解决方法(json方式)
2014/02/04 Javascript
使用GruntJS构建Web程序之构建篇
2014/06/04 Javascript
jQuery针对各类元素操作基础教程
2014/08/29 Javascript
JQuery控制radio选中和不选中方法总结
2015/04/15 Javascript
javascript实现验证IP地址等相关信息代码
2015/05/10 Javascript
javascript中Array()数组函数详解
2015/08/23 Javascript
前端性能优化及技巧
2016/05/06 Javascript
jQuery实现可拖动进度条实例代码
2017/06/21 jQuery
解决ionic和angular上拉加载的问题
2017/08/03 Javascript
移动端效果之Swiper详解
2017/10/09 Javascript
利用jQuery实现简单的拖曳效果实例代码
2017/10/20 jQuery
jQuery 防止相同的事件快速重复触发方法
2018/02/08 jQuery
微信小程序自定义音乐进度条的实例代码
2018/08/28 Javascript
JS实现换肤功能的方法实例详解
2019/01/30 Javascript
小程序click-scroll组件设计
2019/06/18 Javascript
Layui 动态禁止select下拉的例子
2019/09/03 Javascript
vue登录以及权限验证相关的实现
2019/10/25 Javascript
使用Python编写基于DHT协议的BT资源爬虫
2016/03/19 Python
python3获取两个日期之间所有日期,以及比较大小的实例
2018/04/08 Python
Python使用cx_Oracle模块操作Oracle数据库详解
2018/05/07 Python
python实现windows下文件备份脚本
2018/05/27 Python
对python3新增的byte类型详解
2018/12/04 Python
Python实现操纵控制windows注册表的方法分析
2019/05/24 Python
python画图的函数用法以及技巧
2019/06/28 Python
SmartBuyGlasses英国:购买太阳镜和眼镜
2018/01/29 全球购物
德国、奥地利和瑞士最大的旅行和度假门户网站:HolidayCheck
2019/11/14 全球购物
JBL美国官方商店:扬声器、耳机等
2019/12/01 全球购物
采购部部门职责
2013/12/15 职场文书
社区志愿者心得体会
2014/01/03 职场文书
中层领导干部群众路线对照检查材料思想汇报
2014/10/02 职场文书
辞职信如何写
2015/02/27 职场文书
python 爬取豆瓣网页的示例
2021/04/13 Python
pytorch实现加载保存查看checkpoint文件
2022/07/15 Python