Django 多数据库联用(同一个APP的models里不同class用不同数据库)

很多网站有多数据库联用的文章,如自强学堂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
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

原文地址:https://www.cnblogs.com/floodwater/p/9842811.html

时间: 2024-07-30 01:54:30

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

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

今天来说说web框架Django怎么配置使用数据库,也就是传说中MVC(Model View Controller)中的M,Model(模型). 简单介绍一下Django中的MVC: 模型(model):定义你的数据库,一般都在models.py文件中. 视图(view):定义你的HTML等静态网页文件相关,也就是那些html.css.js等前端的东西. 控制器(controller):定义你的业务逻辑相关,就是你的主要代码. 正文开始 首先要在你的Django项目中找到两个文件:setting

Django打造在线教育平台_day_2:新建users app 编写models之扩展user表

1.使用pycharm创建app Tools 工具栏运行 run manage.py Task 输入:startapp users 2.查看django生成的默认的users表auth_user,看字段能否满足需要的,不能就在users/models.py中编写models自定义user表继承auth_user的字段. from django.db import models # AbstractUser包含的Django默认生成的user字段 from django.contrib.auth.

django 将原本数据库中的表导入models中

django 将原本数据库中的表导入models中 连接mysql数据库(创建app,修改settings配置,使用pymysql连接mysql数据库) 根据数据库原有的数据生成对应的models模型文件 生成模型文件 python3 manage.py inspectdb 将模型文件导入app中 python3 manage.py inspectdb > app名/models.py 原文地址:https://www.cnblogs.com/lucky75/p/11380648.html

django 操作数据库--orm(object relation mapping)---models

思想 django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM). PHP:activerecord Java:Hibernate C#:Entity Framework django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表. 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 三层架构 创建表 1.创建Model,之后可以根

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

原文链接: http://www.jianshu.com/p/dbc4193b4f95 Django Model 每一个Django Model都继承自django.db.models.Model 在Model当中每一个属性attribute都代表一个database field 通过Django Model API可以执行数据库的增删改查, 而不需要写一些数据库的查询语句 设置数据库 Django项目建成后, 默认设置了使用SQLite数据库, 在my_blog/my_blog/setting

Django中一个项目里怎么使用两个数据库

在django项目中, 一个工程中存在多个APP应用很常见. 有时候希望不同的APP连接不同的数据库,这个时候需要建立多个数据库连接. 1. 修改项目的 settings 配置 在 settings.py 中配置需要连接的多个数据库连接串 2. 设置数据库的路由规则方法 在settings.py中配置DATABASE_ROUTERS 1DATABASE_ROUTERS = ['Prject.database_router.DatabaseAppsRouter'] Project: 建立的djan

写代码创建数据库,设置位置后比对用可视化界面创建数据库的区别

一.创建数据库 在网上搜了处理方法,稍微改进了一下 create database tttt_1  on PRIMARY (      NAME = test1,      FILENAME='F:\test\test1.mdf',   --此路径必须存在才能建成功    SIZE = 10,      MAXSIZE = UNLIMITED,  --不限制增长    FILEGROWTH = 5  )  LOG ON (      NAME='test1_dat',      FILENAME

JDBC远程从一个MySql数据库中的一张表里面读出数据(这个数据库需要用SSH隧道连接,大约8W条数据),然后分别插入到另一个数据库中的两张表里

package com.eeepay.lzj.db; import java.sql.Connection; import java.sql.Date; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import com.jcraft.jsch.JSch; import com.jcraft.jsc

如何进行数据库,比如ORACLE,SQL SERVER的逆向工程,将数据库导入到PowerDesigner中

如何进行数据库,比如ORACLE,SQL SERVER的逆向工程,将数据库导入到PowerDesigner中 Oracle的反向工程就是指将Oracle中的数据库,当然也可以是SQL Server中的数据库导入到PD中,这个需要建立一个数据库的链接,然后进行逆向工程的操作. 第一步:建立数据库的链接: PowerDesigner建立与数据库的连接,以便生成数据库和从数据库生成到PD中.[Oracle 10G版] PowerDesigner建立与数据库的连接,以便生成数据库和从数据库生成到PD中.