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 相关文章推荐
Easy.Ajax 部分源代码 支持文件上传功能, 兼容所有主流浏览器
Feb 24 Javascript
关于JavaScript的with 语句的使用方法
May 09 Javascript
基于jquery的button默认enter事件(回车事件)。
May 18 Javascript
js中使用使用原型(prototype)定义方法的好处详解
Jul 04 Javascript
基于React实现表单数据的添加和删除详解
Mar 14 Javascript
JS控件bootstrap suggest plugin使用方法详解
Mar 25 Javascript
webpack2.0配置postcss-loader的方法
Aug 17 Javascript
vue-cli脚手架build目录下utils.js工具配置文件详解
Sep 14 Javascript
开发一个Parcel-vue脚手架工具(详细步骤)
Sep 22 Javascript
vue 表单验证按钮事件交由父组件触发的方法
Dec 17 Javascript
vue学习笔记五:在vue项目里面使用引入公共方法详解
Apr 04 Javascript
vue如何限制只能输入正负数及小数
Jul 04 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
星际流派综述
2020/03/04 星际争霸
4月1日重磅发布!《星际争霸II》6.0.0版本更新
2020/04/09 星际争霸
php preg_match_all结合str_replace替换内容中所有img
2008/10/11 PHP
php 中文字符入库或显示乱码问题的解决方法
2010/04/12 PHP
PHP中mysqli_affected_rows作用行数返回值分析
2014/12/26 PHP
php异常处理方法实例汇总
2015/06/24 PHP
PHP中SQL查询语句的id=%d解释(推荐)
2016/12/10 PHP
PHP使用递归算法无限遍历数组示例
2017/01/13 PHP
Javascript优化技巧(文件瘦身篇)
2008/01/28 Javascript
JavaScript 无符号右移运算符
2009/04/17 Javascript
javascript 特性检测并非浏览器检测
2010/01/15 Javascript
Notify - 基于jquery的消息通知插件
2011/10/18 Javascript
中国地区三级联动下拉菜单效果分析
2012/11/15 Javascript
jquery select 设置默认选中的示例代码
2014/02/07 Javascript
jquery实现表单验证并阻止非法提交
2015/07/09 Javascript
JQuery实现DIV其他动画效果的简单实例
2016/09/18 Javascript
canvas滤镜效果实现代码
2017/02/06 Javascript
详解用node.js实现简单的反向代理
2017/06/26 Javascript
Javacript中自定义的map.js  的方法
2017/11/26 Javascript
基于Vue渲染与插件的加载顺序的问题详解
2018/03/05 Javascript
详解JS函数stack size计算方法
2018/06/18 Javascript
使用vue根据状态添加列表数据和删除列表数据的实例
2018/09/29 Javascript
小程序登录之支付宝授权的实现示例
2019/12/13 Javascript
基于JavaScript实现简单的轮播图
2021/03/03 Javascript
浅谈插入排序算法在Python程序中的实现及简单改进
2016/05/04 Python
Python读取图片为16进制表示简单代码
2018/01/19 Python
在Python 中实现图片加框和加字的方法
2019/01/26 Python
Python读取pdf表格写入excel的方法
2021/01/22 Python
HTML5实现页面切换激活的PageVisibility API使用初探
2016/05/13 HTML / CSS
美国旅游网站:Tours4Fun
2017/02/17 全球购物
Zatchels官网:英国剑桥包品牌
2021/01/12 全球购物
办公室岗位职责
2014/02/12 职场文书
学校工作推荐信范文
2014/07/11 职场文书
优秀教师个人材料
2014/12/15 职场文书
合作合同协议书范本
2015/01/27 职场文书
Linux中如何安装并部署Redis
2022/04/18 Servers