很多网站有多数据库联用的文章,如自强学堂http://code.ziqiangxuetang.com/django/django-multi-database.html
大都只讲解如何让不同的app对应不同的数据库,而没有谈到如何让同一个app里的不同class对应不同的数据库。
经过N多次试验,历经好几天时间,终于找出如下的简便易行的途径,而不需要自己造轮子,现总结如下:

方式一:通过数据库路由自动分发Model,无需手动using

settings配置如下:

1、增加了DATABASE_ROUTERS,用于指定路由路径
2、增加了DATABASE_APPS_MAPPING,指定app_label对应的数据库

DBNAME = 'multi_test'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
},
'db1': {
'ENGINE': 'django.db.backends.mysql',
'NAME': DBNAME,
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '127.0.0.1',
'PORT': 3306,
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
},
'db2': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': DBNAME,
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '127.0.0.1',
'PORT': 5432,
},
'db3': {
'ENGINE': 'django.db.backends.dummy',
},
}
connect(DBNAME) #connect to mongodb
SUB_DIR = os.path.basename(os.path.dirname(__file__))
DATABASE_ROUTERS = [
'{}.database_router.DatabaseAppsRouter'.format(SUB_DIR)
]
DATABASE_APPS_MAPPING = {
# example:
#'app_label':'database_name',
'mysql': 'db1',
'postgres': 'db2',
}
# 'mysql', 'postgres'需加到INSTALLED_APPS中,它们是通过startapp创建的两个空app

在settings同目录下增加database_router.py 文件,内容如下:
(直接从自强学堂拷贝,只注释掉print语句,无需做其他更改)

# -*- coding: utf-8 -*-
from django.conf import settings DATABASE_MAPPING = settings.DATABASE_APPS_MAPPING class DatabaseAppsRouter(object):
"""
A router to control all database operations on models for different
databases. In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
will fallback to the `default` database. Settings example: DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
""" def db_for_read(self, model, **hints):
""""Point all read operations to the specific database."""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None def db_for_write(self, model, **hints):
"""Point all write operations to the specific database."""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None def allow_relation(self, obj1, obj2, **hints):
"""Allow any relation between apps that use the same database."""
db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
if db_obj1 and db_obj2:
if db_obj1 == db_obj2:
return True
else:
return False
return None # for Django 1.4 - Django 1.6
def allow_syncdb(self, db, model):
"""Make sure that apps only appear in the related database."""
if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(model._meta.app_label) == db
elif model._meta.app_label in DATABASE_MAPPING:
return False
return None # Django 1.7 - Django 1.11
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure that apps only appear in the related database.
根据app_label的值只在相应的数据库中创建一个表,如果删除该def或
不指定过滤条件,则一个Model会在每个数据库里都创建一个表。
"""
if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(app_label) == db
elif app_label in DATABASE_MAPPING:
return False
return None

models里在class Meta中指定app_label就可以指定它要使用的数据库

例如:settings的DATABASE_APPS_MAPPING中指定app1对应db1、app2对应db2,
那么app1中的Model默认使用db1,而当指定Meta中的app_label为app2时,则改用db2。
注:app_label指定的值须包含在settings的INSTALLED_APPS中,否则makemigrations不会自动创建表。
app1/models.py内容如下:

#coding=utf-8
from django.db import models
from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible
class Animal(models.Model):
name = models.CharField(max_length=20) def __str__(self):
return self.name class Meta:
# 通过app_label来指定要使用的数据库
# 需指定db_table,否则该class的表名会是mysql_animal
# 如果不指定Meta的app_label,会使用默认数据库
app_label = 'mysql'
db_table = 'app1_animal' @python_2_unicode_compatible
class Plant(models.Model):
name = models.CharField(max_length=20) def __str__(self):
return self.name class Meta:
app_label = 'postgres'
db_table = 'app1_plant'

app2/models.py

#coding=utf-8
from django.db import models
from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible
class Fruit(models.Model):
name = models.CharField(max_length=20) def __str__(self):
return self.name class Meta:
app_label = 'mysql' #使用mysql数据库
db_table = 'app2_fruit' #指定表名为app2_fruit @python_2_unicode_compatible
class Nut(models.Model):
name = models.CharField(max_length=20) def __str__(self):
return self.name class Meta:
app_label = 'postgres' #使用postgres数据库
db_table = 'app2_nut' #指定表名为app2_fruit

app1/test.py

from django.test import TestCase

from app1.models import Animal, Plant
from app2.models import Fruit, Nut class ModelsTestCase(TestCase):
# db1 -- mysql
# db2 -- postgres
def setUp(self):
Animal.objects.create(name='db1')
Plant.objects.create(name='db2')
Fruit.objects.create(name='mysql_fruit')
Nut.objects.create(name='post_nut') def test_methods_auto_choose_db(self):
self.assertEqual(Animal.objects.all()[0],
Animal.objects.using('db1').all()[0])
self.assertEqual(Plant.objects.all()[0],
Plant.objects.using('db2').all()[0])
self.assertEqual(Fruit.objects.all()[0],
Fruit.objects.using('db1').all()[0])
self.assertEqual(Nut.objects.all()[0],
Nut.objects.using('db2').all()[0]) self.assertNotEqual(Animal.objects.all()[0],
Fruit.objects.using('db1').all()[0])
self.assertNotEqual(Plant.objects.all()[0],
Nut.objects.using('db2').all()[0])
self.assertNotEqual(Fruit.objects.all()[0],
Plant.objects.using('db2').all()[0])

然后在命令行中运行

python manage.py makemigrations
python manage.py migrate --database=db1
python manage.py migrate --database=db2
python manage.py migrate
python manage.py test

完整代码放在coding上:

git clone https://git.coding.net/zhengwenjie/multi_dbs.git
cd multi_dbs
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt
vi multi_dbs/settings.py #修改数据库名和密码等
alias mg='python manage.py'
mg makemigrations
mg migrate --database=db1
mg migrate --database=db2
mg migrate
mg test

方式二:通过using手动指定数据库

例如settings中的数据库配置如下:

# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases import pymysql
pymysql.install_as_MySQLdb()
from mongoengine import connect
DBNAME = 'multi_test'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
},
'mysql': {
'ENGINE': 'django.db.backends.mysql',
'NAME': DBNAME,
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '127.0.0.1',
'PORT': 3306,
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
},
'postgres': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': DBNAME,
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '127.0.0.1',
'PORT': 5432,
},
'mongo': {
'ENGINE': 'django.db.backends.dummy',
},
}

则查询和创建数据语句如下(不加using为采用default数据库)

from app1.models import House
House.objects.using('mysql').create(name='Tom')
House.objects.using('mysql').get(name='Tom')
House.objects.using('postgres').get_or_create(name='Jim')

作者:waketzheng
链接:https://www.jianshu.com/p/738645fc9230
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Django 多数据库联用(同一个APP的models里不同class用不同数据库)的更多相关文章

  1. django中,如何把所有models模型文件放在同一个app目录下?

    django的每个app目录下,都有自己的models.py文件. 原则上,每个app涉及的数据库,都会定义在这个文件里. 但是,有的数据库,涉及到多个app应用,不是很方便放在一个单独的app里. ...

  2. python之Django学习笔记(二)---Django从工程创建、app创建到表建模在页面的显示

    创建工程: 在命令行中切换目录至需要创建工程的目录,然后在命令行中输入如下命令创建djangoTestPro工程 D:\PycharmProjects\untitled\MyTestProject&g ...

  3. Django models数据库配置以及多数据库联用设置

    今天来说说web框架Django怎么配置使用数据库,也就是传说中MVC(Model View Controller)中的M,Model(模型). 简单介绍一下Django中的MVC: 模型(model ...

  4. Django框架之第二篇--app注册、静态文件配置、form表单提交、pycharm连接数据库、django使用mysql数据库、表字段的增删改查、表数据的增删改查

    本节知识点大致为:静态文件配置.form表单提交数据后端如何获取.request方法.pycharm连接数据库,django使用mysql数据库.表字段的增删改查.表数据的增删改查 一.创建app,创 ...

  5. Django-- 多数据库联用

    django项目中使用多个数据库的方法, 多个数据库的联用 以及多数据库时数据导入导出的方法. 直接给出一种简单的方法吧,想了解更多的到官方教程,点击此处 给每个app都可以单独的设置一个数据库 se ...

  6. Django:URL,Views,Template,Models

    准备工作:熟悉Django命令行工具 django-admin.py 是Django的一个用于管理任务的命令行工具,常用的命令整理如下: <1> 创建一个django工程 : django ...

  7. Django基础,Day2 - 编写urls,views,models

    编写views views:作为MVC中的C,接收用户的输入,调用数据库Model层和业务逻辑Model层,处理后将处理结果渲染到V层中去. polls/views.py: from django.h ...

  8. Django搭建简易博客教程(四)-Models

    原文链接: http://www.jianshu.com/p/dbc4193b4f95 Django Model 每一个Django Model都继承自django.db.models.Model 在 ...

  9. Django中的Project和App的区别

    Django是一个非常流行的用python编写的Web框架,在使用Django之前,我们需要了解一些基本的概念,这样可以在使用Django的时候对其有一个更加深入的把握.本文主要介绍Django中两个 ...

随机推荐

  1. MINIUI grid学习笔记

    grid 控件a.事件的绑定和移除         grid.on("rowclick", fn); //绑定事件 (这个的话类似jquery的绑定事件)         grid ...

  2. web渗透系列--信息收集

    信息收集对于渗透测试前期来说是非常重要的,因为只有我们掌握了目标网站或目标主机足够多的信息之后,我们才能更好地对其进行漏洞检测.正所谓,知己知彼百战百胜! 信息收集的方式可以分为两种:主动和被动. 主 ...

  3. [NoSql注入] MongoDB学习

    0x00 安装 下载:http://dl.mongodb.org/dl/win32/x86_64 安装:http://www.runoob.com/mongodb/mongodb-window-ins ...

  4. C++线程同步 -- windows

    简介: 在一般情况下,创建一个线程是不能提高程序的执行效率的,所以要创建多个线程.但是多个线程同时运行的时候可能调用线程函数,在多个线程同时对同一个内存地址进行写入, 由于CPU时间调度上的问题,写入 ...

  5. source insight支持查看makefile、kconfig以及.s代码方法

    在用sourceinsight查看linux内核源码的时候,大家会发现不能查看源码中的makefile和kconfig代码,即不能搜索到makefile和kconfig文件.这是因为source in ...

  6. netty之IO演进之路

    常见IO类型: 传统的同步阻塞I/O编程<BIO> 基于NIO的非阻塞编程 基于NIO2.0的异步非阻塞AIO编程 BIO缺点: 没有数据缓冲区,I/O性能存在问题 没有Channel概念 ...

  7. vue 父组件使用keep-alive和infinite-scroll导致在子组件触发父组件的infinite-scroll方法

    (vue.js)vue 父组件使用keep-alive和infinite-scroll导致在子组件触发父组件的infinite-scroll方法”问题疑问,本网通过在网上对“ (vue.js)vue ...

  8. 导入Excel扩展名是.xls 和.xlsx的

    1.首先是导入Excel2003以前(包括2003)的版本,扩展名是.xls 的 /** * 操作Excel2003以前(包括2003)的版本,扩展名是.xls * @param templetFil ...

  9. php上传大文件

    1.使用PHP的创始人 Rasmus Lerdorf 写的APC扩展模块来实现(http://pecl.php.net/package/apc) APC实现方法: 安装APC,参照官方文档安装,可以使 ...

  10. OI多项式 简单学习笔记

    咕咕咕 先开个坑(其实是存模板来了) 一些特别简单的前置东西qwq 复数的计算 复数相加:向量相加,复数相乘.复数相乘:模长相乘,旋转量相加(就是复平面坐标轴逆时针旋转的角度) (当然也可以直接使用c ...