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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端