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自建的表的!


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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容