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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM