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 相关文章推荐
不同浏览器的怪癖小结
Jul 11 Javascript
HTML Dom与Css控制方法
Oct 25 Javascript
suggestion开发小结以及对键盘事件的总结(针对中文输入法状态)
Dec 20 Javascript
JavaScript高级程序设计 阅读笔记(十七) js事件
Aug 14 Javascript
使用jQuery jqPlot插件绘制柱状图
Dec 18 Javascript
jQuery定义背景动态切换效果的方法
Mar 23 Javascript
jquery对Json的各种遍历方法总结(必看篇)
Sep 29 Javascript
jQuery的Cookie封装,与PHP交互的简单实现
Oct 05 Javascript
JQuery学习总结【二】
Dec 01 Javascript
JavaScript实现弹窗效果代码分析
Mar 09 Javascript
Vue-router 类似Vuex实现组件化开发的示例
Sep 15 Javascript
Node.js console控制台简单用法分析
Jan 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
php实现的遍历文件夹下所有文件,编辑删除
2010/01/05 PHP
PHP json_encode() 函数详解及中文乱码问题
2015/11/05 PHP
给WordPress的编辑后台添加提示框的代码实例分享
2015/12/25 PHP
CI框架(CodeIgniter)实现的数据库增删改查操作总结
2018/05/23 PHP
PHP实现一维数组与二维数组去重功能示例
2018/05/24 PHP
YII框架模块化处理操作示例
2019/04/26 PHP
Prototype使用指南之array.js
2007/01/10 Javascript
js 页面刷新location.reload和location.replace的区别小结
2009/12/24 Javascript
Javascript中产生固定结果的函数优化技巧
2013/01/16 Javascript
常用的JavaScript验证正则表达式汇总
2013/11/26 Javascript
node.js不得不说的12点内容
2014/07/14 Javascript
js代码实现点击按钮出现60秒倒计时
2021/01/28 Javascript
学习JavaScript设计模式之观察者模式
2020/04/22 Javascript
jQuery+json实现动态创建复杂表格table的方法
2016/10/25 Javascript
JavaScript实现简单的四则运算计算器完整实例
2017/04/28 Javascript
Nodejs进阶之服务端字符编解码和乱码处理
2017/09/04 NodeJs
angular4 共享服务在多个组件中数据通信的示例
2018/03/30 Javascript
详解Puppeteer 入门教程
2018/05/09 Javascript
JavaScript实现封闭区域布尔运算的示例代码
2018/06/25 Javascript
jQuery使用ajax传递json对象到服务端及contentType的用法示例
2020/03/12 jQuery
解决vue-router 嵌套路由没反应的问题
2020/09/22 Javascript
Python模块学习 filecmp 文件比较
2012/08/27 Python
Python判断Abundant Number的方法
2015/06/15 Python
Python多线程原理与用法详解
2018/08/20 Python
Python爬取某平台短视频的方法
2021/02/08 Python
Html5实现首页动态视频背景的示例代码
2019/09/25 HTML / CSS
怎么可以提高数据库查询数据的速度
2014/06/28 面试题
应届毕业生的个人自我鉴定
2013/10/24 职场文书
高中自我评价分享
2013/12/05 职场文书
创意广告词
2014/03/17 职场文书
卖车协议书范本4篇
2014/10/01 职场文书
金秋助学感谢信
2015/01/21 职场文书
客户经理岗位职责大全
2015/04/09 职场文书
开学第一周值周总结
2015/07/16 职场文书
2015年秋学期师德师风建设工作总结
2015/10/23 职场文书
用Python远程登陆服务器的步骤
2021/04/16 Python