使用Vue和Django开发Web系统全流程五(Django项目中的多数据库配置)

 

一个web系统可能会用到多个数据库,下面以Mysql、Oracle为例

 

运行环境为:python==3.7.2,django==1.11.20,cx-oracle==7.12,mysqlClient==1.42,oracle数据库是11版本

默认的SQLite这里不再赘述,我将他去掉了,这里主要说Mysql数据库和Oracle数据库,下图是代码结构:

1. 首先在配置文件里配置Mysql和Oracle,config.ini内容如下:

[Mysql-Database]
host = 111.xx.xx.xx
port = 3306
name = xxx
user = xxx
password = xxx

[Oracle-Database]
host = 118.xxx.xxx.xxx
port = 1521
name = xxx
user = xxx
password = xxx

 

2. 修改setting文件,添加mysql app和oracle app

"""
Django settings for multiple_database project.

Generated by 'django-admin startproject' using Django 2.2.1.

For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/
"""
import configparser
import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'qaplf-ft+g$=89ll-p4d8dxit+y_p)jqfr^^b$6)a-#2xrqlwr'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app_Mysql',
    'app_Oracle'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'multiple_database.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'multiple_database.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases

config_init = configparser.ConfigParser()
config_init.read(os.path.join(BASE_DIR, 'config/config.ini'))

# config_Json = ''
# with open(os.path.join(BASE_DIR, 'config/config.json'), 'rt') as f:
#     config_Json = json.load(f)
DATABASES = {

    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': config_init.get("Mysql-Database", "host"),
        'PORT': config_init.get("Mysql-Database", "port"),
        'NAME': config_init.get("Mysql-Database", "name"),
        'USER': config_init.get("Mysql-Database", "user"),
        'PASSWORD': config_init.get("Mysql-Database", "password")
    },
    'db_Oracle': {
        'ENGINE': 'django.db.backends.oracle',
        'HOST': config_init.get("Oracle-Database", "host"),
        'PORT': config_init.get("Oracle-Database", "port"),
        'NAME': config_init.get("Oracle-Database", "name"),
        'USER': config_init.get("Oracle-Database", "user"),
        'PASSWORD': config_init.get("Oracle-Database", "password")
    },
}

DATABASE_ROUTERS = ['multiple_database.database_router.DatabaseAppsRouter']
# appName,dbName
DATABASE_APPS_MAPPING = {
    'app_Mysql': 'default',
    'app_Oracle': 'db_Oracle',
}


# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/

USE_I18N = True
USE_L10N = True
USE_TZ = True


TIME_ZONE = 'Asia/Shanghai'
LANGUAGE_CODE = 'zh-hans'
DEFAULT_CHARSET = "utf-8"

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/

STATIC_URL = '/static/'

我将setting文件中的关键部分截了下来,放到了下面:

其中:DATABASE_APPS_MAPPING是多数据库配置的核心,这里以map存储

DATABASE_ROUTERS = ['multiple_database.database_router.DatabaseAppsRouter']
# appName,dbName
DATABASE_APPS_MAPPING = {
    'app_Mysql': 'default',
    'app_Oracle': 'db_Oracle',
}

注意:这里要按需修改,配置不正确就会导致数据库无法同步(models生成表)和映射(表生成models):

multiple_database是你的Django项目名称

app_mysql和app_Oracle是项目中app名称,

db_Mysql和db_Oracle是DATABASES中配置的数据库名称

 

3. 添加database_router.py文件,这个文件来源于自强学堂

原文地址为:https://code.ziqiangxuetang.com/django/django-multi-database.html

# -*- 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):
        if db in DATABASE_MAPPING.values():
            return DATABASE_MAPPING.get(app_label) == db
        elif app_label in DATABASE_MAPPING:
            return False
        return None

 

4 .将mysql数据库中的表结构映射到Model中:

python manage.py inspectdb --database=db_Mysql > app_Mysql/models.py

 

5. 将Oracle数据库中的表结构映射到Model中:

python manage.py inspectdb --database=db_Oracle > app_Oracle/models.py

上述命令执行完成后,各APP下面将产生对应数据库的models

我这里的oracle是11版本的,所以要使用2.0以下的django版本,如果使用的是oracle12版本的,建议使用Django2.0以上,

上述命令都是在Terminal中执行的,亲测可行

上面的语句执行完成后,会分别在两个app下面生成对应的models内容,这里不再展示! 

  

6. 在mysql app下的Model.py中添加新的表结构:

 首先将数据库原有的表结构执行以下命令,即初始化原有model:

python manage.py makemigrations app_Mysql

 初始化完成会生成0001_inital.py文件,然后我们在models.py中添加新的表结构

class Demo(models.Model):
    l_unit_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255, blank=True, null=True)
    class Meta:
        db_table = 'T_Demo'

然后再次执行下面的makemigrations命令,该命令会生成0002_demo.py文件:

python manage.py makemigrations app_Mysql

为了验证makemigrations 命令是否正确执行,在Terminal中输入以下语句,命令将会打印出对应的sql语句:

python manage.py sqlmigrate app_Mysql 0002

 然后Terminal会输出:

-- Create model Demo
--
CREATE TABLE `T_Demo` (`l_unit_id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(255) NULL);
COMMIT;

 

然后再执行migrate命令,我们新建的表就会同步到Mysql了:

python manage.py migrate app_Mysql

 Terminal将打印下面的内容:

(venv) C:\Users\X250\Desktop\multiple_database>python manage.py migrate app_Mysql
Operations to perform:
  Apply all migrations: app_Mysql
Running migrations:
  Applying app_Mysql.0001_initial... OK
  Applying app_Mysql.0002_demo... OK

 

使用Navicat发现,新建的Demo表已经创建到了数据库中:

 

注意makemigrations和migrate命令后跟的的参数,参数错误,将导致同步失败

 

 7. 在app_Oracle的Model.py中添加新的表结构: 

和app_Mysql一样的操作,但是结果却完全不同,真的很恶心。。。。

 和Mysql一样,先执行makemigrations命令:

python manage.py makemigrations app_Oracle

 然后再执行migrate命令:

python manage.py migrate --database=db_Oracle

再添加Demo表,步骤和mysql一样,但是添加新表时,就会出现下图的问题,如图:

(venv) C:\Users\X250\Desktop\multiple_database>python manage.py makemigrations app_Oracle
Migrations for 'app_Oracle':
  app_Oracle\migrations\0002_demo2.py
    - Create model Demo2

(venv) C:\Users\X250\Desktop\multiple_database>python manage.py sqlmigrate app_Oracle 0002
BEGIN;
--
-- Create model Demo2
--
COMMIT;

下面是mysql的建表语句:

-- Create model Demo
--
CREATE TABLE `T_Demo` (`l_unit_id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY);
COMMIT;

对比发现,Oracle创建 Demo2时,里面是不含有任何sql语句,而mysql却包含了建表语句。

这个应该是Django1.11和Oracle11两者间的bug。

为了绕过这个问题,只能在Oracle中先建立表,通过反射生成model进行,真的很智障:

如图,

1. 先在oracle创建表,字段名一定要大写

2. 删除migrations文件夹中的内容,_init_.py不删除

 

3. 清除数据库中django_migrations中和app_Oracle相关的内容,我这里删除过了

注意:默认的是mysql数据库,所以应该去mysql数据库里进行删除

4. 删除models.py文件中的所以内容



5. 执行反射命令

python manage.py inspectdb --database=db_Oracle > app_Oracle/models.py

然后demo表的models就映射到了models.py文件

6. 执行 makemigrations 命令

python manage.py makemigrations app_Oracle

ok,Oracle无法创建表的问题,我们绕了过去,现在要验证多数据库配置能否被django调用。

 

8. 多数据库校验

1. 启动管理工具,并创建super用户,注意:super用户在默认的数据库中创建

创建的流程请参考这个链接:https://www.runoob.com/django/django-admin-manage-tool.html

2. 在各app下添加admin对指定models的管理,如图

3. 启动web项目,打开管理页面:

 

4. 操作app_Mysql下的demo试一下,没有问题:

 

5. 操作app_Oracle下的demo试一下,没有问题

 

注意:如果这里报出ID:invalid identifer的错误,请确认Demo表中含有主键,且字段名为大写!!!

注意:如果这里报出ID:invalid identifer的错误,请确认Demo表中含有主键,且字段名为大写!!!

注意:如果这里报出ID:invalid identifer的错误,请确认Demo表中含有主键,且字段名为大写!!!

 

至此,oracle和mysql这两个数据的配置完成

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值