python通过mongoengine中connect函数连接多个数据库

mongoengine支持程序同时连接多个数据库,这些数据库可以位于一个或多个mongo之中,通过alias名称区分不同的连接即可。

可以通过switch_db切换到不同的数据库,进行读写操作,switch_db其实是一个上下文管理器,通过和with语句一起使用,能够保证切换数据库的影响范围。

由于个人电脑上没有安装mongodb,以下代码示例中访问的mongodb通过mongoengine提供的mock mongodb替代,只需要在connect函数参数中加上is_mock=True参数,并且安装有mongomock package(pip install mongomock)即可。

 1 #!/usr/bin/env python
 2 # coding=utf-8
 3 from mongoengine import connect
 4 from mongoengine.document import Document
 5 from mongoengine.fields import StringField, IntField
 6 from mongoengine.context_managers import switch_db
 7 
 8 
 9 # 连接不同db
10 connect(alias='testdbA', is_mock=True)
11 connect(alias='testdbB', is_mock=True)
12 connect(alias='testdbC', is_mock=True)
13 
14 
15 class User(Document):
16     meta = {
17             # db_alias用于指定User绑定的mongo连接,和connect函数中的alias对应
18             'db_alias': 'testdbA',
19             }
20     uname = StringField(max_length=63)
21     uid = StringField(max_length=64)
22     age = IntField(default=0)
23 
24 
25 def create_record(uname, uid, age):
26     user = User()
27     user.uname = uname
28     user.uid = uid
29     user.age = age
30     return user
31 
32 def print_records(records):
33     # 输出User类此时绑定的db连接名称,并输出其记录个数
34     records = list(User.objects.all())
35     print('{} count:{}, records:'.format(User._meta['db_alias'], len(records)))
36     for rc in records:
37         print('    {}|{}|{}'.format(rc['uname'], rc['uid'], rc['age']))
38 
39 
40 records = list(User.objects.all())
41 print_records(records)
42 create_record('Ace', 'AX001', 10).save()
43 print_records(records)
44 
45 # switch到testdbB连接
46 with switch_db(User, 'testdbB'):
47     print_records(records)
48     create_record('Bob', 'BX001', 11).save()
49     print_records(records)
50 
51 # switch到testdbC连接
52 with switch_db(User, 'testdbC'):
53     print_records(records)
54     create_record('Carl', 'CX001', 12).save()
55     print_records(records)

 

 

 运行结果如下:

$ python mongo_test.py
testdbA count:0, records:
testdbA count:1, records:
    Ace|AX001|10
testdbB count:0, records:
testdbB count:1, records:
    Bob|BX001|11
testdbC count:0, records:
testdbC count:1, records:
    Carl|CX001|12

 

switch_db其实就是一个简单的上下文管理器,源码位于mongoengine/context_managers.py当中,其实就是在switch_db对象初始化时、进入with代码块前、离开with代码块后,通过改变db_alias和collection两个字段对应的取值,实现了不同mongodb连接的切换,代码简单注释版本如下:

 1 class switch_db(object):
 2     """switch_db alias context manager.
 3 
 4     Example ::
 5 
 6         # Register connections
 7         register_connection('default', 'mongoenginetest')
 8         register_connection('testdb-1', 'mongoenginetest2')
 9 
10         class Group(Document):
11             name = StringField()
12 
13         Group(name='test').save()  # Saves in the default db
14 
15         with switch_db(Group, 'testdb-1') as Group:
16             Group(name='hello testdb!').save()  # Saves in testdb-1
17     """
18 
19     def __init__(self, cls, db_alias):
20         """Construct the switch_db context manager
21 
22         :param cls: the class to change the registered db
23         :param db_alias: the name of the specific database to use
24         """
25         self.cls = cls
26         # 存储切换前的collection
27         self.collection = cls._get_collection()
28         # 设置为要切换的db连接名称
29         self.db_alias = db_alias
30         # 存储切换前的原db连接名称
31         self.ori_db_alias = cls._meta.get('db_alias', DEFAULT_CONNECTION_NAME)
32     def __enter__(self):
33         """Change the db_alias and clear the cached collection."""
34         # 进入with代码块前触发
35         # 修改为本次指定的db连接名称
36         self.cls._meta['db_alias'] = self.db_alias
37         # 将collection置为None,于是之后会重新根据新的db连接获取collection
38         self.cls._collection = None
39         return self.cls
40 
41     def __exit__(self, t, value, traceback):
42         """Reset the db_alias and collection."""
43         # 退出with代码块后触发
44         # 恢复为切换前的db连接名称
45         self.cls._meta['db_alias'] = self.ori_db_alias
46         # 恢复为切换前的collection
47         self.cls._collection = self.collection

 

posted @ 2017-11-14 00:52  及时  阅读(5694)  评论(0编辑  收藏  举报