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和php通信乱码问题解决方法
Apr 15 Python
python字典get()方法用法分析
Apr 17 Python
pip install urllib2不能安装的解决方法
Jun 12 Python
python 统计一个列表当中的每一个元素出现了多少次的方法
Nov 14 Python
Python如何处理大数据?3个技巧效率提升攻略(推荐)
Apr 15 Python
深入浅析Python中的迭代器
Jun 04 Python
Python collections模块使用方法详解
Aug 28 Python
python 实现Flask中返回图片流给前端展示
Jan 09 Python
Pytorch maxpool的ceil_mode用法
Feb 18 Python
Python中的None与 NULL(即空字符)的区别详解
Sep 24 Python
scrapy-redis分布式爬虫的搭建过程(理论篇)
Sep 29 Python
pandas按条件筛选数据的实现
Feb 20 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写的MySQL数据库用户认证系统代码
2007/03/22 PHP
php面向对象 字段的声明与使用
2012/06/14 PHP
探讨如何在PHP开启gzip页面压缩实例
2013/06/09 PHP
去除php注释和去除空格函数分享
2014/03/13 PHP
浅析PHP中的 inet_pton 网络函数
2019/12/16 PHP
JavaScript中创建类/对象的几种方法总结
2013/11/29 Javascript
jquery validate demo 基础
2015/10/29 Javascript
js实现常用排序算法
2016/08/09 Javascript
Javascript数组中push方法用法分析
2016/10/31 Javascript
VUE 更好的 ajax 上传处理 axios.js实现代码
2017/05/10 Javascript
微信小程序使用Socket的实例
2017/09/19 Javascript
javascript高仿热血传奇游戏实现代码
2018/02/22 Javascript
node.js中express模块创建服务器和http模块客户端发请求
2019/03/06 Javascript
vue 实现搜索的结果页面支持全选与取消全选功能
2019/05/10 Javascript
JS简单数组排序操作示例【sort方法】
2019/05/17 Javascript
重置Redux的状态数据的方法实现
2019/11/18 Javascript
微信小程序实现天气预报功能(附源码)
2020/12/10 Javascript
推荐下python/ironpython:从入门到精通
2007/10/02 Python
python显示天气预报
2014/03/02 Python
python数组过滤实现方法
2015/07/27 Python
python 回调函数和回调方法的实现分析
2016/03/23 Python
python中星号变量的几种特殊用法
2016/09/07 Python
python Matplotlib画图之调整字体大小的示例
2017/11/20 Python
numpy 进行数组拼接,分别在行和列上合并的实例
2018/05/08 Python
python中的插值 scipy-interp的实现代码
2018/07/23 Python
win10系统下Anaconda3安装配置方法图文教程
2018/09/19 Python
python按行读取文件并找出其中指定字符串
2019/08/08 Python
简单了解python filter、map、reduce的区别
2020/01/14 Python
使用Python获取当前工作目录和执行命令的位置
2020/03/09 Python
css3实现3D文本悬停改变效果的示例代码
2019/01/16 HTML / CSS
简单的HTML5初步入门教程
2015/09/29 HTML / CSS
澳大利亚领先的在线葡萄酒零售商:Get Wines Direct
2018/03/27 全球购物
Bata印度官网:源自欧洲舒适鞋履品牌
2020/01/30 全球购物
毕业生应聘求职信
2014/07/10 职场文书
学生抄袭作业的检讨书
2014/10/02 职场文书
ajax请求前端跨域问题原因及解决方案
2021/10/16 Javascript