mongoengine中collection名字自动生成机制浅探

Posted To be a better programmer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mongoengine中collection名字自动生成机制浅探相关的知识,希望对你有一定的参考价值。

项目碰到要使用mongodb的场景,以前只听过这一强大的文档数据库,但一直没有真正使用过,参考一下项目中已有的使用代码,是通过import mongoengine这一模块实现python服务对db中collection的增删查改。

mongoengine的项目网站http://mongoengine.org 中介绍到:

MongoEngine is a Document-Object Mapper (think ORM, but for document databases) for working with MongoDB from Python.

大意是,MongoEngine是一个针对在Python中方便使用MongoDB的文档对象的映射器(类似ORM(Object Relational Mapping),但是是针对文档数据库)

参考已有的代码时发现,代码通过定义一个继承mongoengine.Document(定义于mongoengine/document.py文件中)的Python类和db中的collection建立了映射关系,通过对类的操作即可实现对db中对应collection的操作。

例如UserInfo的类定义如下:

class UserInfo(Document):
    """
        用户数据对象
    """
    meta = { 
        db_alias: user,
        indexes: [
            user_id,
            user_type
        ]   
    }   
 
    user_type = IntField(default=USER_COOP)
    user_id = StringField(default=‘‘, max_length=64)
    nickname = StringField(detault=‘‘, max_length=16)
 
    ctime = DateTimeField(default=datetime.utcnow)
    mtime = DateTimeField(default=datetime.utcnow)   

其中meta用于定义类的一些元信息,如db_alias代表要访问的mongodb中具体的db名称,indexes则定义索引(用处?)。

然而其中并没有发现指定访问的collection名称的代码,估计是根据某种特殊规则从类的信息推断生成出来的,这引起了我的好奇,想要探究一番其生成原理。

通过远程登录上mongodb,使用"show collections"查看user db中的collection列表,发现了名叫user_info的collection,实际测试也确认UserInfo类查询的具体数据来源于其中

通过进一步参考官方文档,发现meta中可以通过指定"collection"的key-value对人工指明UserInfo类绑定的collection,然而上述代码中并没有用到这一机制。官方文档中说到mongodb默认通过将Document子类的名称转换为小写来作为db中对应collection的名称:

By default, the MongoDB collection used to store documents created using a Document subclass will be the name of the subclass converted to lowercase. A different collection may be specified by providing collection to the meta dictionary in the class definition.

然而这样的话UserInfo对应的名称应该是userinfo,而不是user_info才对。

使用开源软件的优势果断凸显出来了,拜读源码,研究个清楚。

查找源码发现mongoengine中的Document类中定义有类成员my_metaclass和__metaclass,其类型均为TopLevelDocumentMetaclass,collection名称根据UserInfo自动生成的逻辑就在这里面。

# The __metaclass__ attribute is removed by 2to3 when running with Python3

# my_metaclass is defined so that metaclass can be queried in Python 2 & 3

my_metaclass = TopLevelDocumentMetaclass
    __metaclass__ = TopLevelDocumentMetaclass

TopLevelDocumentMetaclass的定义在mongoengine/base/metaclasses.py中:

class TopLevelDocumentMetaclass(DocumentMetaclass):

    """Metaclass for top-level documents (i.e. documents that have their own

    collection in the database.

    """

    ...

针对collection名称自动生成的逻辑就在其__new__函数之中,其会在meta中没有collection字段时,根据以下代码片段生成默认collection名称:

        # Set default collection name

        if collection not in meta:

           meta[collection] = ‘‘.join(_%s % c if c.isupper() else c

                                         for c in name).strip(_).lower()

看到这里就一切了然了,将name中的所有大写字母转换为小写+‘_‘的形式(UserInfo->_user_info),而后strip两边的‘_‘(_user_info->user_info)

以上是关于mongoengine中collection名字自动生成机制浅探的主要内容,如果未能解决你的问题,请参考以下文章

Python中使用MongoEngine3

Python中使用MongoEngine2

MongoEngine:关闭连接

Python中使用MongoEngine

我可以将 MOTOR 用于 mongoengine 吗?

Python中使用MongoEngine1