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 相关文章推荐
[推荐]javascript 面向对象技术基础教程
Mar 03 Javascript
JavaScript对象、属性、事件手册集合方便查询
Jul 04 Javascript
IE的fireEvent方法概述及应用
Feb 22 Javascript
jQuery 网易相册鼠标移动显示隐藏效果实现代码
Mar 31 Javascript
jquery实现保存已选用户
Jul 21 Javascript
jQuery后代选择器用法实例
Dec 23 Javascript
javascript实现的图片切割多块效果实例
May 07 Javascript
socket.io实现在线群聊功能
Apr 07 Javascript
JS字符串去除连续或全部重复字符的实例
Mar 08 Javascript
如何使node也支持从url加载一个module详解
Jun 05 Javascript
jQuery实现表单动态添加数据并提交的方法
Jul 19 jQuery
微信小程序学习总结(四)事件与冒泡实例分析
Jun 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(2)
2006/10/09 PHP
php zip文件解压类代码
2009/12/02 PHP
php实现概率性随机抽奖代码
2016/01/02 PHP
你需要知道的10个最佳javascript开发实践小结
2012/04/15 Javascript
Javascript图像处理—平滑处理实现原理
2012/12/28 Javascript
jQuery之排序组件的深入解析
2013/06/19 Javascript
计算新浪Weibo消息长度(还可以输入119字)
2013/07/02 Javascript
如何设置一定时间内只能发送一次请求
2014/02/28 Javascript
用JavaScript实现用一个DIV来包装文本元素节点
2014/09/09 Javascript
jQuery添加和删除指定标签的方法
2015/12/16 Javascript
JavaScript数组去重由慢到快由繁到简(优化篇)
2016/08/26 Javascript
jquery实现刷新随机变化样式特效(tag标签样式)
2017/02/03 Javascript
MUI 解决动态列表页图片懒加载再次加载不成功的bug问题
2017/04/13 Javascript
PHP实现记录代码运行时间封装类实例教程
2017/05/08 Javascript
react中的ajax封装实例详解
2017/10/17 Javascript
在vue项目中集成graphql(vue-ApolloClient)
2018/09/08 Javascript
javascript动态创建对象的属性详解
2018/11/07 Javascript
Python学习笔记之os模块使用总结
2014/11/03 Python
Python MySQLdb Linux下安装笔记
2015/05/09 Python
Python中查看文件名和文件路径
2017/03/31 Python
Python数据分析之双色球统计单个红和蓝球哪个比例高的方法
2018/02/03 Python
TensorFlow实现AutoEncoder自编码器
2018/03/09 Python
python计算两个地址之间的距离方法
2018/06/09 Python
Python Django的安装配置教程图文详解
2019/07/17 Python
python boto和boto3操作bucket的示例
2020/10/30 Python
手把手教你用Django执行原生SQL的方法
2021/02/18 Python
支持IE8的纯css3开发的响应式设计动画菜单教程
2014/11/05 HTML / CSS
基于HTML5的齿轮动画特效
2016/02/29 HTML / CSS
英国豪华真皮和布艺沙发销售网站:Darlings of Chelsea
2018/01/05 全球购物
工程地质勘察专业大学生求职信
2013/10/13 职场文书
历史学专业个人的自我评价
2013/10/13 职场文书
材料物理专业大学毕业生求职信
2013/10/15 职场文书
名人演讲稿范文
2013/12/28 职场文书
2016年国陪研修感言
2015/11/18 职场文书
使用css样式设计一个简单的html登陆界面的实现
2021/03/30 HTML / CSS
MYSQL数据库使用UTF-8中文编码乱码的解决办法
2021/05/26 MySQL