zoukankan      html  css  js  c++  java
  • Django——连接多个数据库的实现方式

    Django——连接多个数据库的实现方式


     

      最近刚刚忙完手头的工作,所以决定把这一个项目里面的坑陆续梳理出来,一方面以后自己回顾的时候有个参考算是备忘,另一方面希望能帮到遇到跟我一样问题的兄弟。

    *首先声明,我所用的版本是python3.5和Django2.0.4,公司使用的是Django,没有用restframework。
    一、应用场景

      首先一个Django项目里通常会有多个app,现在很多公司在这多个app中都是共用的一个数据库。在这种场景中是不存在所谓连多个数据库的。那以我的个人经历来说,公司近两个月让我陆陆续续做了一些小的系统(都是用于公司内部数据分拣的),因为每个都很急用,所以就做完一个上线一个,数据库和项目都部在不同服务器上了。直到有一天我们老总把我叫过去:“小肖啊,你抽时间把你做的几个系统合一下,咱们把它合成一个系统。就是登陆以后,出一个系统选择页面,选哪个就进那个系统。”

      之后我一番奋战,把代码什么的合并到一起了。但是,发现数据不在一个库里,王炸!那么就有两种选择:

      1.把所有的模型都通过默认的数据库放在一起,那么这样做就需要把之前处理的数据抽出来,并且对模型进行修改,把一些重复的表名进行一些区分;

      2.是依然让数据存在之前的库里,把这些数据库迁移出来,抽取出Django自建的表,然后通过不同的数据库进行不同操作,这样也做到了不同系统间的数据的隔离。

      所以最后我选用了第二种方案来做这个事情。

    二、代码实现

      代码中主要是三个部分,settings、models以及自己写的一个类。首先看看我们写的那个类:

     1 from django.conf import settings
     2 
     3 DATABASE_MAPPING = settings.DATABASE_APPS_MAPPING
     4 
     5 class DatabaseAppsRouter(object):
     6     """
     7     A router to control all database operations on models for different
     8     databases.
     9 
    10     In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
    11     will fallback to the `default` database.
    12 
    13     Settings example:
    14 
    15     DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
    16     """
    17 
    18     def db_for_read(self, model, **hints):
    19         """"Point all read operations to the specific database."""
    20         """将所有读操作指向特定的数据库。"""
    21         if model._meta.app_label in DATABASE_MAPPING:
    22             return DATABASE_MAPPING[model._meta.app_label]
    23         return None
    24 
    25     def db_for_write(self, model, **hints):
    26         """Point all write operations to the specific database."""
    27         """将所有写操作指向特定的数据库。"""
    28         if model._meta.app_label in DATABASE_MAPPING:
    29             return DATABASE_MAPPING[model._meta.app_label]
    30         return None
    31 
    32     def allow_relation(self, obj1, obj2, **hints):
    33         """Allow any relation between apps that use the same database."""
    34         """允许使用相同数据库的应用程序之间的任何关系"""
    35         db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
    36         db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
    37         if db_obj1 and db_obj2:
    38             if db_obj1 == db_obj2:
    39                 return True
    40             else:
    41                 return False
    42         else:
    43             return None
    44 
    45     def allow_syncdb(self, db, model):
    46         """Make sure that apps only appear in the related database."""
    47         """确保这些应用程序只出现在相关的数据库中。"""
    48         if db in DATABASE_MAPPING.values():
    49             return DATABASE_MAPPING.get(model._meta.app_label) == db
    50         elif model._meta.app_label in DATABASE_MAPPING:
    51             return False
    52         return None
    53 
    54     def allow_migrate(self, db, app_label, model=None, **hints):
    55         """Make sure the auth app only appears in the 'auth_db' database."""
    56         """确保身份验证应用程序只出现在“authdb”数据库中。"""
    57         if db in DATABASE_MAPPING.values():
    58             return DATABASE_MAPPING.get(app_label) == db
    59         elif app_label in DATABASE_MAPPING:
    60             return False
    61         return None

      这个类主要是规范了数据库的一些读写操作。要注意,这个文件是放在和settings.py同级的目录下的。代码逻辑比较好理解,我就不解释了。用的时候直接复制粘贴一把梭,然后自己再做一些逻辑处理上的修改就可以了。

      在settings中是配置三个地方,代码如下:

     1 # Database
     2 # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
     3 
     4 DATABASES = {
     5     'default':{
     6         'NAME': 'venn',
     7         'ENGINE': 'sql_server.pyodbc',
     8         'HOST': '127.0.0.1',
     9         'PORT': '1433',
    10         'USER': 'venndata',
    11         'PASSWORD': 'venndata',
    12         'OPTIONS':{
    13             'driver':'SQL Server Native Client 10.0',
    14         }
    15     },
    16     'venn': {
    17         'NAME': 'venn',
    18         'ENGINE': 'sql_server.pyodbc',
    19         'HOST': '127.0.0.1',
    20         'PORT': '1433',
    21         'USER': 'venndata',
    22         'PASSWORD': 'venndata',
    23         'OPTIONS':{
    24             'driver':'SQL Server Native Client 10.0',
    25         }
    26     },
    27     'vip_cluster': {
    28         'NAME': 'vip_cluster',
    29         'ENGINE': 'sql_server.pyodbc',
    30         'HOST': '127.0.0.1',
    31         'PORT': '1433',
    32         'USER': 'venndata',
    33         'PASSWORD': 'venndata',
    34         'OPTIONS':{
    35             'driver':'SQL Server Native Client 10.0',
    36         }
    37     },
    38     'catecheck': {
    39         'NAME': 'catecheck',
    40         'ENGINE': 'sql_server.pyodbc',
    41         'HOST': '127.0.0.1',
    42         'PORT': '1433',
    43         'USER': 'venndata',
    44         'PASSWORD': 'venndata',
    45         'OPTIONS':{
    46             'driver':'SQL Server Native Client 10.0',
    47         }
    48     },
    49     'skucheck': {
    50         'NAME': 'skucheck',
    51         'ENGINE': 'sql_server.pyodbc',
    52         'HOST': '127.0.0.1',
    53         'PORT': '1433',
    54         'USER': 'venndata',
    55         'PASSWORD': 'venndata',
    56         'OPTIONS':{
    57             'driver':'SQL Server Native Client 10.0',
    58         }
    59     },
    60     'barcode': {
    61         'NAME': 'barcode',
    62         'ENGINE': 'sql_server.pyodbc',
    63         'HOST': '127.0.0.1',
    64         'PORT': '1433',
    65         'USER': 'venndata',
    66         'PASSWORD': 'venndata',
    67         'OPTIONS':{
    68             'driver':'SQL Server Native Client 10.0',
    69         }
    70     }
    71 }
    72 
    73 
    74 DATABASE_ROUTERS = ['vennsystem.database_router.DatabaseAppsRouter']
    75 
    76 
    77 DATABASE_APPS_MAPPING = {
    78     # example:
    79     # 'app_name':'database_name',
    80     'venncheck': 'skucheck',
    81     'barcode': 'barcode',
    82     'catecheck': 'catecheck',
    83     'clust': 'vip_cluster',
    84     'the_entrance': 'venn',
    85     'admin': 'venn',
    86     'auth': 'venn',
    87     'contenttypes': 'venn',
    88     'sessions': 'venn',
    89 }

      DATABASES大家都知道,是配置数据库连接的(这里要注意的是我用的是sql server数据库,里面OPTIONS是非常重要的参数,一定要把这个加进去,不然跑不起来)。default是默认的数据库,在这里可以为{},但是一旦为空不可以执行'python manage.py migrate'(会在下个部分说怎么处理)

      之后是DATABASE_ROUTERS这个指向的是我们自己写的那个类(['项目名.文件名.类名'])。最后是路由分配,把app的名字和数据库对应起来。 

      在模型中的部分特别简单,只要加两行代码就可以解决:

    1 class Href(models.Model):
    2     name = models.CharField(max_length=100)
    3     path = models.CharField(max_length=100)
    4 
    5     class Meta:
    6         app_label = 'the_entrance'

      就是这样的东西,加上app_label以后就会指明所属的app。

    三、执行

      执行的顺序就是大家熟悉的了:

      1.python manage.py makemigrations

      之后的稍有不同:

      2.python manage.py migrate --database=skucheck

         python manage.py migrate --database=barcode

         ......

         python manage.py migrate(只有默认数据库不为空时才可以这么实用,若为空则是用上面的方法)

         其实在这里没有特别的执行顺序,但是我个人建议大家是最后执行migrate(即默认数据库)。另外要注意一点,admin、auth、contenttypes和sessions是一定要在一个app里被makemigrations放到一个XXXX_initial.py文件中的,不然你怎么migrate都不会有这些Django自建的表的!


    ****最后的最后一定要注意:已经不在一个库里了,没法跨库建立约束关系,放弃外键,老实的一步步查!****

     

  • 相关阅读:
    【odoo14】【好书学习】第一章、安装odoo的开发环境
    echarts 根据geojson 数据绘制区域图(精确到镇)
    百度地图 获取具体位置经纬度
    js 实时监听滚动条状态 判断滚动条位置
    vue cli3 使用elemet-plus
    关于vue告警 More than 1 blank line not allowed
    vue cli3 创建项目
    intelliJ idea 自动修复eslint语法问题
    函数式编程
    二分法
  • 原文地址:https://www.cnblogs.com/XiaoBoya/p/9209491.html
Copyright © 2011-2022 走看看