• Django 多数据库配置与使用总结


    Django 多数据库配置与使用总结

     

    By:授客 QQ:103355122

     

    #实践环境

    Win 10

     

    Python 3.5.4

     

    Django-2.0.13.tar.gz

    官方下载地址:

    https://www.djangoproject.com/download/2.0.13/tarball/

     

    #需求描述

    项目开发中,部分业务功能的实现,需要跨数据库查询,并且想通过Django自带ORM来实现

     

    #解决方案

    为Django配置多数据库,具体操作步骤如下:

     

    1、修改项目settings.py DATABASES配置

    打开settings.py ,修改DATABASES配置—-为需要连接的数据库新增配置(本例中以mysql数据库配置为例,假设需要链接两个数据库)

     

    # ...略
    
    DATABASES = {
         # 默认数据库配置
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'database_name', # 自定义数据库名称
            'USER': 'db_username',
            'PASSWORD': 'db_user_password',
            'HOST': '127.0.0.1',
            'PORT': '3306',
            'CONN_MAX_AGE': 30,
            'OPTION': {
                'init_command': 'SET default_storage_engine=INNODB'
            }
        },
        'secondDb': { #secondDb代表第二个数据库的配置#该名称可自定义
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'second_db_name', 
            'USER': 'db_username ',
            'PASSWORD': 'db_user_password',
            'HOST': '127.0.0.1',
            'PORT': '3306',
            'CONN_MAX_AGE': 30,
            'OPTION': {
                'init_command': 'SET default_storage_engine=INNODB'
            },
        },
    #...略
    }
    

      

    为了方便描述下文内容,这里暂且把上述的 default,secondDb等称为“数据库配置结点”

     

    2、修改项目settings.py DATABASE_ROUTERS路由配置

     

    打开settings.py ,修改DATABASE_ROUTERS配置(如果不存在,则新增该配置项)

     

    DATABASES = {

    #...略

    }

     

    DATABASE_ROUTERS = ['Package.database_routers.DatabaseRouters']

     

    说明:

    Package: 路由规则文件所在包(一般是项目根目录下,与项目同名的包目录,或者app根目录(包目录))

     

    database_routers: 定义路由规则的.py文件名称,该文件名称可以自定义

     

    DatabaseRouters:上述.py中,定义路由规则的类名称,该类名可自定义

     

    DATABASE_ROUTERS为列表,所以,可以配置多个不同的路由

     

    3、建立app应用和数据库的映射关系

    在settings.py中新增app和数据库的映射关系(如果没有的话),即针对指定app,配置其需要连接的数据库

     

    APP_DATABASE_MAPPING = { # 映射配置名称,可自定义

    'mysite': ' defualt', # 格式说明 'app名称':'数据库配置结点' # 注意,这里的“app名称”,必须在settings.INSTALLED_APPS中已注册,“数据库配置结点”要同 settings.DATABASE 保持对应,两者皆不能随便自定义

    'myblog': 'secondDb',

    }

     

    4、配置不允许执行migration操作的app(确切的说是app的model)

    APPS_NOT_ALLOW_MIGRATE = ['myblog'] # 配置 app-label 为 myblog 的 model 不允许执行migration操作

     

     

    5、创建数据库路由规则

    在项目根目录下,与项目同名的目录下(与 settings.py 文件位于同一目录)创建路由规则.py文件(例中为 database_routers.py )

     

    项目代码工程结构目录如下

    TMP

    |--TMP

        |--settings.py

        |--database_routers.py

    |--manage.py

    |--...略

    |--mysite

    |--myblog

     

    database_routers.py内容如下:

     

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    
    '''
    @Author :shouke
    '''
    
    from django.conf import settings
    
    DATABASE_MAPPING = settings.APP_DATABASE_MAPPING
    
    DATABASES_NOT_ALLOW_MIGRATE = settings.APPS_NOT_ALLOW_MIGRATE
    
    
    class DatabaseRouters(object):
        def db_for_read(self, model, **hints):
            """"指定mode进行读取操作时应使用的数据库, 如果返回None则表示使用默认数据库"""
    
            if model._meta.app_label in DATABASE_MAPPING:
                return DATABASE_MAPPING[model._meta.app_label]
            return None
    
    
        def db_for_write(self, model, **hints):
            """指定mode进行写入操作时应使用的数据库, 如果返回None则表示使用默认数据库"""
    
            if model._meta.app_label in DATABASE_MAPPING:
                return DATABASE_MAPPING[model._meta.app_label]
            return None
    
    
        def allow_relation(self, obj1, obj2, **hints):
            """控制是否允许obj1和obj2建立关联关系,供外键和多对多操作使用,如果返回True则表示允许,如果返回False则阻止建立关联关系,如果返回None则表示仅允许在相同数据库内的对象建立关联关系(备注:笔者亲测,执行save()保存包含关联外键对象,或者通过某个对象获取关联外键对象,该函数都不会被执行     
            """
    
            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
    
    
        def allow_migrate(self, db, app_label, model=None, **hints):
            """指定是否允许在别名为db的数据库上运行迁移操作。如果允许运行,则返回True;否则返回False、None"""
    
            if app_labelin DATABASES_NOT_ALLOW_MIGRATE:
                return False
            else:
                return True
    

      

     

    6、创建mode表

    在对应app中,创建对应数据表的models,不过,需要注意的是,需要根据上述路由规则,及实际需求,考虑是否为model指定app_label,如果不指定,在默认数据库上执行相关操作。

     

    以下为样例数据表 mode

    class BugType(models.Model):
        id = models.AutoField(primary_key=True, verbose_name='自增id')
        bug_type = models.CharField(max_length=50, verbose_name='bug类型')
    
        class Meta:
            db_table = 'tb_bug_type'
            app_label = 'mysite'
            verbose_name = 'bug类型表'
            verbose_name_plural = verbose_name
    
    class SprintBug(models.Model):
        id = models.AutoField(primary_key=True, verbose_name='自增id')
        name = models.CharField(max_length=10, verbose_name='bug名称')
        but_type_id = models.IntegerField()
    
        class Meta:
            db_table = 'tb_sprint_bug'
            app_label = 'myblog'
            verbose_name = '迭代bug表'
            verbose_name_plural = verbose_name
    

      

     

     

    说明:

    这里假设SprintBug Model对应数据表为项目中需要跨数据库查询的且已存在的数据表,所以,希望在当前项目中执行migrate操作操作时,不对它进行创建、或者修改其数据表,仅供ORM操作使用,为了达到这个目的,需要显示指定 db_table 为该据表在数据库中的表名,并且显示指定app_label值,并确保该 app_label 值存在上述settings.APPS_NOT_ALLOW_MIGRATE列表中(根据上述路由规则,app_label值存在settings.APPS_NOT_ALLOW_MIGRATE列表中的mode不允许执行migration操作)。

     

    7、执行数据库迁移操作

    如果还没执行迁移操作,需要先执行迁移操作,以便创建、修改model对应的数据库表

    python manage.py makemigrationsappName

    python manage.pymigrate

     

     

    说明:

    如果希望执行migrate操作时,对应app对应model的migrations操作,在指定数据库中执行,则需要使用 --database 选项,否则,没指定app_label的model对应数据表相关操作将在默认数据库中执行。

     

    例子:把mysite的数据库迁移操作放到 myAppDb1 代表的数据库中执行。

    python manage.py makemigrationsmysite

    python manage.py--database=myAppDb1 # 注意,--database选项值实为settings.py中目标数据库的“数据库配置结点”,且该选项值不能加引号、双引号,否则会报错

     

    这样以后,其它所有的创建、查询、删除等操作就和普通一样操作就可以了,无需再使用类似

    models.User.objects.using(dbname).all()这样的方式来操作。

       

    #参考链接

    https://docs.djangoproject.com/en/2.1/topics/db/multi-db/

     

      

     

  • 相关阅读:
    moment.js常用时间示例,时间管理
    RabbitMQ用户增删及权限控制
    CDN概念基本介绍
    在LinkedIn的 Kafka 生态系统
    发行说明
    Kafka 1.0版本发布
    redis应用场景及实例
    Redis哨兵集群
    redis-订阅与发布
    redis事务
  • 原文地址:https://www.cnblogs.com/shouke/p/14136052.html
Copyright © 2020-2023  润新知