Django多数据库的实现过程详解


Posted in Python onAugust 01, 2019

有些项目可能涉及到使用多个数据库的情况,方法很简单。

1.在settings中设定DATABASE

比如要使用两个数据库:

DATABASES = {
  'default': {
    'NAME': 'app_data',
    'ENGINE': 'django.db.backends.postgresql',
    'USER': 'postgres_user',
    'PASSWORD': 's3krit'
  },
  'users': {
    'NAME': 'user_data',
    'ENGINE': 'django.db.backends.mysql',
    'USER': 'mysql_user',
    'PASSWORD': 'priv4te'
  }
}

这样就确定了2个数据库,别名一个为default,一个为user。数据库的别名可以任意确定。

default的别名比较特殊,一个Model在路由中没有特别选择时,默认使用default数据库。

当然,default也可以设置为空:

DATABASES = {
  'default': {},
  'users': {
    'NAME': 'user_data',
    'ENGINE': 'django.db.backends.mysql',
    'USER': 'mysql_user',
    'PASSWORD': 'superS3cret'
  },
  'customers': {
    'NAME': 'customer_data',
    'ENGINE': 'django.db.backends.mysql',
    'USER': 'mysql_cust',
    'PASSWORD': 'veryPriv@ate'
  }
}

这样,因为没有了默认的数据库,就需要为所有的Model,包括使用的第三方库中的Model做好数据库路由选择。

2.为需要做出数据库选择的Model规定app_label

class MyUser(models.Model):
  ...
   class Meta:
    app_label = 'users'

3.写Database Routers

Database Router用来确定一个Model使用哪一个数据库,主要定义以下四个方法:

db_for_read(model, **hints)

规定model使用哪一个数据库读取。

db_for_write(model, **hints)

规定model使用哪一个数据库写入。

allow_relation(obj1, obj2, **hints)

确定obj1和obj2之间是否可以产生关联, 主要用于foreign key和 many to many操作。

allow_migrate(db, app_label, model_name=None, **hints)

确定migrate操作是否可以在别名为db的数据库上运行。

一个完整的例子:

数据库设定:

DATABASES = {
  'default': {},
  'auth_db': {
    'NAME': 'auth_db',
    'ENGINE': 'django.db.backends.mysql',
    'USER': 'mysql_user',
    'PASSWORD': 'swordfish',
  },
  'primary': {
    'NAME': 'primary',
    'ENGINE': 'django.db.backends.mysql',
    'USER': 'mysql_user',
    'PASSWORD': 'spam',
  },
  'replica1': {
    'NAME': 'replica1',
    'ENGINE': 'django.db.backends.mysql',
    'USER': 'mysql_user',
    'PASSWORD': 'eggs',
  },
  'replica2': {
    'NAME': 'replica2',
    'ENGINE': 'django.db.backends.mysql',
    'USER': 'mysql_user',
    'PASSWORD': 'bacon',
  },
}

如果想要达到如下效果:

app_label为auth的Model读写都在auth_db中完成,其余的Model写入在primary中完成,读取随机在replica1和replica2中完成。

auth:

class AuthRouter(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 'auth_db'
    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 'auth_db'
    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_migrate(self, db, app_label, model_name=None, **hints):
    """
    Make sure the auth app only appears in the 'auth_db'
    database.
    """
    if app_label == 'auth':
      return db == 'auth_db'
    return None

这样app_label为auth的Model读写都在auth_db中完成,允许有关联,migrate只在auth_db数据库中可以运行。

其余的:

import random
 
class PrimaryReplicaRouter(object):
  def db_for_read(self, model, **hints):
    """
    Reads go to a randomly-chosen replica.
    """
    return random.choice(['replica1', 'replica2'])
 
  def db_for_write(self, model, **hints):
    """
    Writes always go to primary.
    """
    return 'primary'
 
  def allow_relation(self, obj1, obj2, **hints):
    """
    Relations between objects are allowed if both objects are
    in the primary/replica pool.
    """
    db_list = ('primary', 'replica1', 'replica2')
    if obj1._state.db in db_list and obj2._state.db in db_list:
      return True
    return None
 
  def allow_migrate(self, db, app_label, model_name=None, **hints):
    """
    All non-auth models end up in this pool.
    """
    return True

这样读取在随机在replica1和replica2中完成,写入使用primary。

最后在settings中设定:

DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']

就可以了。

进行migrate操作时:

$ ./manage.py migrate
$ ./manage.py migrate --database=users

migrate操作默认对default数据库进行操作,要对其它数据库进行操作,可以使用--database选项,后面为数据库的别名。

与此相应的,dbshell,dumpdata,loaddata命令都有--database选项。

也可以手动的选择路由:

查询:

>>> # This will run on the 'default' database.
>>> Author.objects.all()
 
>>> # So will this.
>>> Author.objects.using('default').all()
 
>>> # This will run on the 'other' database.
>>> Author.objects.using('other').all()

保存:

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

移动:

>>> p = Person(name='Fred')
>>> p.save(using='first') # (statement 1)
>>> p.save(using='second') # (statement 2)

以上的代码会产生问题,当p在first数据库中第一次保存时,会默认生成一个主键,这样使用second数据库保存时,p已经有了主键,这个主键如果未被使用不会产生问题,但如果先前被使用了,就会覆盖原先的数据。

有两个解决方法;

1.保存前清除主键:

>>> p = Person(name='Fred')
>>> p.save(using='first')
>>> p.pk = None # Clear the primary key.
>>> p.save(using='second') # Write a completely new object.

2.使用force_insert

>>> p = Person(name='Fred')
>>> p.save(using='first')
>>> p.save(using='second', force_insert=True)

删除:

从哪个数据库取得的对象,从哪删除

>>> u = User.objects.using('legacy_users').get(username='fred')
>>> u.delete() # will delete from the `legacy_users` database

如果想把一个对象从legacy_users数据库转移到new_users数据库:

>>> user_obj.save(using='new_users')
>>> user_obj.delete(using='legacy_users')

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
phpsir 开发 一个检测百度关键字网站排名的python 程序
Sep 17 Python
详解Python函数可变参数定义及其参数传递方式
Aug 02 Python
在python中pandas读文件,有中文字符的方法
Dec 12 Python
python 提取key 为中文的json 串方法
Dec 31 Python
django创建最简单HTML页面跳转方法
Aug 16 Python
python图片二值化提高识别率代码实例
Aug 24 Python
如何为Python终端提供持久性历史记录
Sep 03 Python
python 多维高斯分布数据生成方式
Dec 09 Python
PyCharm 专业版安装图文教程
Feb 20 Python
python matplotlib实现将图例放在图外
Apr 17 Python
Python操作Word批量生成合同的实现示例
Aug 28 Python
Python 用户输入和while循环的操作
May 23 Python
Python解决pip install时出现的Could not fetch URL问题
Aug 01 #Python
numpy.meshgrid()理解(小结)
Aug 01 #Python
Python-接口开发入门解析
Aug 01 #Python
Python列表(list)所有元素的同一操作解析
Aug 01 #Python
详解numpy.meshgrid()方法使用
Aug 01 #Python
解决安装python3.7.4报错Can''t connect to HTTPS URL because the SSL module is not available
Jul 31 #Python
numpy中的meshgrid函数的使用
Jul 31 #Python
You might like
解析link_mysql的php版
2013/06/30 PHP
php自定义分页类完整实例
2015/12/25 PHP
IE不出现Flash激活框的小发现的js实现方法
2007/09/07 Javascript
一个javascript图片阅览组件
2010/11/09 Javascript
js获取select选中的option的text示例代码
2013/12/19 Javascript
jquery数组封装使用方法分享(jquery数组遍历)
2014/03/25 Javascript
jQuery选择器全集详解
2014/11/24 Javascript
详细解密jsonp跨域请求
2015/04/15 Javascript
JS实现仿QQ面板的手风琴效果折叠菜单代码
2015/09/11 Javascript
Javascript简单实现面向对象编程继承实例代码
2015/11/27 Javascript
AngularJS 避繁就简的路由
2016/07/01 Javascript
Angular2入门--架构总览
2017/03/29 Javascript
详解使用JS如何制作简单的ASCII图与单极图
2017/03/31 Javascript
ztree实现权限横向显示功能
2017/05/20 Javascript
解决包含在label标签下的checkbox在ie8及以下版本点击事件无效果兼容的问题
2019/10/27 Javascript
微信小程序自定义头部导航栏(组件化)
2019/11/15 Javascript
Javascript中的this,bind和that使用实例
2019/12/05 Javascript
查找Vue中下标的操作(some和findindex)
2020/08/12 Javascript
[01:44]《为梦想出发》—联想杯DOTA2完美世界全国高校联赛
2015/09/30 DOTA
[04:40]2016国际邀请赛中国区预选赛全程TOP10镜头集锦
2016/07/01 DOTA
深入理解NumPy简明教程---数组2
2016/12/17 Python
WINDOWS 同时安装 python2 python3 后 pip 错误的解决方法
2017/03/16 Python
python 监听salt job状态,并任务数据推送到redis中的方法
2019/01/14 Python
详解基于python的多张不同宽高图片拼接成大图
2019/09/26 Python
python如何实现不用装饰器实现登陆器小程序
2019/12/14 Python
总结html5自定义属性有哪些
2020/04/01 HTML / CSS
基本款天堂:Everlane
2017/05/13 全球购物
MAC彩妆澳洲官网:M·A·C AU
2021/01/17 全球购物
Java语言的优势
2015/01/10 面试题
工作推荐信范文
2014/05/10 职场文书
建筑安全生产责任书
2014/07/22 职场文书
学习保证书100字
2015/02/26 职场文书
毕业欢送会致辞
2015/07/29 职场文书
导游词之无锡梅园
2019/11/28 职场文书
FP-growth算法发现频繁项集——发现频繁项集
2021/06/24 Python
使用canvas对video视频某一刻截图功能
2021/09/25 HTML / CSS