博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django 多数据库联用(同一个APP的models里不同class用不同数据库)
阅读量:6921 次
发布时间:2019-06-27

本文共 6894 字,大约阅读时间需要 22 分钟。

很多网站有多数据库联用的文章,如自强学堂

大都只讲解如何让不同的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-8from django.db import modelsfrom 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-8from django.db import modelsfrom 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 TestCasefrom app1.models import Animal, Plantfrom app2.models import Fruit, Nutclass 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 makemigrationspython manage.py migrate --database=db1python manage.py migrate --database=db2python manage.py migratepython manage.py test

完整代码放在coding上:

git clone https://git.coding.net/zhengwenjie/multi_dbs.gitcd multi_dbsvirtualenv venvsource venv/bin/activatepip install -r requirements.txtvi 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/#databasesimport pymysqlpymysql.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 HouseHouse.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
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/floodwater/p/9842811.html

你可能感兴趣的文章
中国HBase技术社区第四届MeetUp上海站——HBase应用实践专场
查看>>
Unity射线检测的用法总结
查看>>
react native ios打包 编译成功 Archive失败报错问题
查看>>
Java源码阅读之ReentrantLock - lock和unLock方法
查看>>
win7以及win10系统升级
查看>>
阿里云ECS建网站(建站)超详细全套完整图文教程!菜鸟必看!
查看>>
Elasticsearch Reindex性能提升10倍+实战
查看>>
史上最快Docker入门!(一)-容器技术和Docker简介
查看>>
阿里巴巴联手新加坡培养 AI 博士,每月 2.5 万元奖学金
查看>>
9- 快速上手Linux玩转典型应用- git版本管理
查看>>
Spark内部原理之运行原理一
查看>>
SpringBoot_04_热部署
查看>>
史上最全的 Python 3 类型转换指南
查看>>
【程序媛晒83行代码】素颜女神,轻松分析用户画像
查看>>
碰撞与鲜血:人类与自动驾驶的坎坷摩擦
查看>>
Android内存管理
查看>>
事务日志已满,原因为“ACTIVE_TRANSACTION”
查看>>
开源 | 蚂蚁金服开源:关系数据的可视化引擎 G6 2.0
查看>>
Vue:router的beforeEach与afterEach钩子函数
查看>>
移动端APP CSS Reset及注意事项CSS重置
查看>>