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宝典学习笔记(下)
Jan 10 Javascript
jQuery源码分析之jQuery.fn.each与jQuery.each用法
Jan 23 Javascript
JS动态添加Table的TR,TD实现方法
Jan 28 Javascript
老生常谈onBlur事件与onfocus事件(js)
Jul 09 Javascript
JS实现的系统调色板完整实例
Dec 21 Javascript
JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome
Jan 05 Javascript
React 组件中的 bind(this)示例代码
Sep 16 Javascript
详解async/await 异步应用的常用场景
May 13 Javascript
JavaScript对象字面量和构造函数原理与用法详解
Apr 18 Javascript
React实现全选功能
Aug 25 Javascript
javascript this指向相关问题及改变方法
Nov 19 Javascript
vue自定义组件实现双向绑定
Jan 13 Vue.js
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判断网络文件是否存在的方法
2015/03/12 PHP
微信公众平台DEMO(PHP)
2016/05/04 PHP
php中array_unshift()修改数组key注意事项分析
2016/05/16 PHP
bcastr2.0 通用的图片浏览器
2006/11/22 Javascript
javascript语句中的CDATA标签的意义
2007/05/09 Javascript
经典海量jQuery插件 大家可以收藏一下
2010/02/07 Javascript
XMLHTTP 乱码的解决方法(UTF8,GB2312 编码 解码)
2011/01/12 Javascript
JS图片无缝、平滑滚动代码
2014/03/11 Javascript
chrome调试javascript详解
2015/10/21 Javascript
JS简单获取及显示当前时间的方法
2016/08/03 Javascript
关于javascript原型的修改与重写(覆盖)差别详解
2016/08/31 Javascript
基于jQuery插件jqzoom实现的图片放大镜效果示例
2017/01/23 Javascript
vue2.0使用v-for循环制作多级嵌套菜单栏
2018/06/25 Javascript
Vue动态控制input的disabled属性的方法
2018/06/26 Javascript
webpack4.0+vue2.0利用批处理生成前端单页或多页应用的方法
2019/06/28 Javascript
python实现zabbix发送短信脚本
2018/09/17 Python
python 模拟银行转账功能过程详解
2019/08/06 Python
python 提取文件指定列的方法示例
2019/08/07 Python
wxPython实现分隔窗口
2019/11/19 Python
tensorflow 环境变量设置方式
2020/02/06 Python
Python 格式化打印json数据方法(展开状态)
2020/02/27 Python
Pygame框架实现飞机大战
2020/08/07 Python
通俗易懂了解Python装饰器原理
2020/09/17 Python
数控专业毕业生求职信范文
2013/09/21 职场文书
婚礼证婚人证婚词
2014/01/08 职场文书
企业总经理岗位职责
2014/02/13 职场文书
中药学专业求职信
2014/05/31 职场文书
任命书模板
2014/06/04 职场文书
国际政治学专业推荐信
2014/09/26 职场文书
企业领导班子四风对照检查材料
2014/09/27 职场文书
2014年销售助理工作总结
2014/12/01 职场文书
农村婚礼司仪主持词
2015/06/29 职场文书
运动会广播稿50字
2015/08/19 职场文书
教师理论学习心得体会
2016/01/21 职场文书
利用Python网络爬虫爬取各大音乐评论的代码
2021/04/13 Python
python实现自定义日志的具体方法
2021/05/28 Python