Django使用多数据库的方法


Posted in Javascript onSeptember 06, 2017

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

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')

总结

以上所述是小编给大家介绍的Django使用多数据库的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
总结一些js自定义的函数
Aug 05 Javascript
vs2003 js文件编码问题的解决方法
Mar 20 Javascript
js仿百度有啊通栏展示效果实现代码
May 28 Javascript
在jquery中的ajax方法怎样通过JSONP进行远程调用
Apr 04 Javascript
浅谈jQuery中 wrap() wrapAll() 与 wrapInner()的差异
Nov 12 Javascript
不想让浏览器运行javascript脚本的方法
Nov 20 Javascript
开启BootStrap学习之旅
May 04 Javascript
使用jQuery制作遮罩层弹出效果的极简实例分享
May 12 Javascript
JavaScript基于原型链的继承
Jun 22 Javascript
Vue.js实现微信过渡动画左右切换效果
Jun 13 Javascript
详解JavaScript的内存空间、赋值和深浅拷贝
Apr 17 Javascript
ES6 Iterator接口和for...of循环用法分析
Jul 31 Javascript
node.js实现微信JS-API封装接口的示例代码
Sep 06 #Javascript
详解require.js配置路径的用法和css的引入
Sep 06 #Javascript
js canvas实现简单的图像扩散效果
Jun 28 #Javascript
vue 2.0项目中如何引入element-ui详解
Sep 06 #Javascript
jQuery实现的弹幕效果完整实例
Sep 06 #jQuery
JavaScrip数组删除特定元素的几种方法总结
Sep 06 #Javascript
jQuery实现的文字逐行向上间歇滚动效果示例
Sep 06 #jQuery
You might like
php fsockopen中多线程问题的解决办法[翻译]
2011/11/09 PHP
解析Linux下Varnish缓存的配置优化
2013/06/20 PHP
CodeIgniter辅助之第三方类库third_party用法分析
2016/01/20 PHP
浅谈PHP的数据库接口和技术
2016/12/09 PHP
ExtJS 2.0实用简明教程 之Border区域布局
2009/04/29 Javascript
让GoogleCode的SVN下的HTML文件在FireFox下正常显示.
2009/05/25 Javascript
Javascript解决常见浏览器兼容问题的12种方法
2010/01/04 Javascript
JS 有名函数表达式全面解析
2010/03/19 Javascript
超酷的网页音乐播放器DewPlayer使用方法
2010/12/18 Javascript
Javascript变量函数浅析
2011/09/02 Javascript
Javascript中的几种URL编码方法比较
2015/01/23 Javascript
JavaScript String(字符串)对象的简单实例(推荐)
2016/08/31 Javascript
Bootstrap table简单使用总结
2017/02/15 Javascript
JS控件bootstrap datepicker使用方法详解
2017/03/25 Javascript
微信小程序request出现400的问题解决办法
2017/05/23 Javascript
手把手教你搭建ES6的开发运行环境
2017/07/11 Javascript
使用vue制作探探滑动堆叠组件的实例代码
2018/03/07 Javascript
详解JavaScript事件循环机制
2018/09/07 Javascript
node省市区三级数据性能测评实例分析
2019/11/06 Javascript
bootstrap实现嵌套模态框的实例代码
2020/01/10 Javascript
jQuery插件实现图片轮播效果
2020/10/19 jQuery
[05:45]Ti4观战指南(下)
2014/07/07 DOTA
python调用fortran模块
2016/04/08 Python
Python常用算法学习基础教程
2017/04/13 Python
Python中扩展包的安装方法详解
2017/06/14 Python
基于python(urlparse)模板的使用方法总结
2017/10/13 Python
PyCharm中Matplotlib绘图不能显示UI效果的问题解决
2020/03/12 Python
哥伦比亚最大的网上商店:Linio哥伦比亚
2016/09/25 全球购物
简述安装Slackware Linux系统的过程
2012/01/12 面试题
护理职业应聘自荐书
2013/09/29 职场文书
打架检讨书100字
2014/01/19 职场文书
大学生职业生涯规划书汇总
2014/03/20 职场文书
我的求职择业计划书
2014/04/04 职场文书
2014年体育工作总结
2014/11/24 职场文书
2015年检验科工作总结
2015/04/27 职场文书
结婚主持人致辞
2015/07/28 职场文书