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 相关文章推荐
个人总结的一些关于String、Function、Array的属性和用法
Jan 10 Javascript
13 个JavaScript 性能提升技巧分享
Jul 26 Javascript
精心挑选的12款优秀的基于jQuery的手风琴效果插件和教程
Aug 22 Javascript
js动态设置div的值下例子
Oct 29 Javascript
js与jQuery 获取父窗、子窗的iframe
Dec 20 Javascript
Javascript 是你的高阶函数(高级应用)
Jun 15 Javascript
JS验证全角与半角及相互转化的介绍
May 18 Javascript
利用JavaScript对中文(汉字)进行排序实例详解
Jun 18 Javascript
详解node-ccap模块生成captcha验证码
Jul 01 Javascript
微信小程序实时聊天WebSocket
Jul 05 Javascript
opencv 识别微信登录验证滑动块位置
Aug 07 Javascript
产制造追溯系统之通过微信小程序实现移动端报表平台
Jun 03 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
模拟SQLSERVER的两个函数:dateadd(),datediff()
2006/10/09 PHP
php无序树实现方法
2015/07/28 PHP
PHP iconv()函数字符编码转换的问题讲解
2019/03/22 PHP
模拟电子签章盖章效果的jQuery插件源码
2013/06/24 Javascript
JS小功能(操作Table--动态添加删除表格及数据)实现代码
2013/11/28 Javascript
javascript避免数字计算精度误差的方法详解
2014/03/05 Javascript
jQuery实现的多选框多级联动插件
2014/05/02 Javascript
Javascript学习笔记之函数篇(六) : 作用域与命名空间
2014/11/23 Javascript
jquery.mousewheel实现整屏翻屏效果
2015/08/30 Javascript
JavaScript深度复制(deep clone)的实现方法
2016/02/19 Javascript
js格式化时间的简单实例
2016/11/27 Javascript
前端axios下载excel文件(二进制)的处理方法
2018/07/31 Javascript
深入理解js A*寻路算法原理与具体实现过程
2018/12/13 Javascript
Angular7.2.7路由使用初体验
2019/03/01 Javascript
Python的面向对象编程方式学习笔记
2016/07/12 Python
Python 2与Python 3版本和编码的对比
2017/02/14 Python
python并发编程之线程实例解析
2017/12/27 Python
python获取酷狗音乐top500的下载地址 MP3格式
2018/04/17 Python
对dataframe进行列相加,行相加的实例
2018/06/08 Python
pygame游戏之旅 添加游戏界面按键图形
2018/11/20 Python
python正则-re的用法详解
2019/07/28 Python
python打造爬虫代理池过程解析
2019/08/15 Python
tensorflow 实现打印pb模型的所有节点
2020/01/23 Python
Python如何脚本过滤文件中的注释
2020/05/27 Python
python实现图像外边界跟踪操作
2020/07/13 Python
重构Python代码的六个实例
2020/11/25 Python
利用纯CSS3实现tab选项卡切换示例代码
2016/09/21 HTML / CSS
精致的手工皮鞋:Shoe Embassy
2019/11/08 全球购物
俄罗斯最大的灯具网站:Fandeco
2020/03/14 全球购物
PatPat香港:婴童服饰和亲子全家装在线购物
2020/09/27 全球购物
毕业生动漫设计求职信
2013/10/11 职场文书
英语专业毕业生自荐信范文
2013/12/31 职场文书
招聘专员岗位职责
2014/03/07 职场文书
促销活动计划书
2014/05/02 职场文书
基于HTML十秒做出淘宝页面
2021/10/24 HTML / CSS
SpringCloud项目如何解决log4j2漏洞
2022/04/10 Java/Android