更优雅的使用Motor MongoDB Python 异步ORM

1,161 阅读1分钟

官方例子

  • motor官网给的查询示例
import asyncio
import motor.motor_asyncio

client = motor.motor_asyncio.AsyncIOMotorClient('mongodb://localhost:27017')
db = client['test_database']
collection = db['test_collection']

async def do_find_one():
    document: dict = await db.test_collection.find_one({'i': {'$lt': 1}})
    print(document.get('_id'))  # 结果以字典类型返回,这句打印出:ObjectId('...')

loop = asyncio.get_event_loop()
loop.run_until_complete(do_find_one())

思考

  • test_collection集合里有哪些字段,分别代表什么意思?
  • 开始是如何设置字段和index的呢?
  • 结果能不能用对象的方式操作?dict -> object
  • 通过json的object_hook参数,或者pip install addict
  • 可以转,但转换后的结果能不能对应上集合,是否有更优雅的方式?
  • 如果有个类似ORM可以定义Model就好了!

看看这个

from mongoengine import Document, DynamicDocument, fields

class BaseModel(Document):
    """模型基类,公共方法"""
    meta = {"abstract": True}

    def to_dict(self):
        """模型对象转字典,并把id对象字符串化"""
        data = self.to_mongo().to_dict()
        if "_id" in data:
            data["id"] = data.pop("_id").__str__()
        return data

    @classmethod
    def load_motor(cls, document: dict):
        """加载单个motor数据文档,转成mongoengine对象"""
        if "_id" in document:
            document["id"] = document.pop("_id")
        return cls(**document)

class TestCollection(DynamicDocument, BaseModel):
    """测试集合"""

    meta = {
        "collection": "test_collection",
        "db_alias": "test_database",
        "indexes": [
            {"fields": ("name", "code"), 'unique': True}
        ],
        "ordering": ["i"],
    }
    i = fields.IntField()
    code = fields.IntField(verbose_name="编号")
    name = fields.StringField(max_length=255, verbose_name="名称")
  • 官方代码的do_find_one异步方法修改成这样:
async def do_find_one():
    document: dict = await db.test_collection.find_one({'i': {'$lt': 1}})
    # 手动转换motor结果字典为ORM对象
    # 也可以试试手动给find_one出来的结果类手动增加to_model方法,不过我试了,但没成功
    document: TestCollection = TestCollection.load_motor(document)
    print(document.id))  # 结果即可用对象的方式访问属性值,这句打印出:ObjectId('...')
    return document.to_dict()  # 也可以直接再转回dict
  • 不知道是不是有点麻烦呢?不过我觉得使用结果时减少了很多[""]取值,以及有Model的存在,至少让代码更可读一些,不然别人接手后,除了看MongoDB数据字段,否则无法知道需要查什么数据,或者这个字段到底是什么意思。