Search code examples
pythonmongodbumongo

Can't get list of model fields


I need to get list of model fields like:

@instance.register
class Todo(Document):
    title = fields.StringField(required=True, default='Name')
    description = fields.StringField()
    created_at = fields.DateTimeField()
    created_by = fields.StringField()
    priority = fields.IntegerField()

to

[
    'title',
    'description',
    'created_at',
    'created_by',
    'priority'
]

So, I have function that returns list of fields

def get_class_properties(cls):
    attributes = inspect.getmembers(cls, lambda a: not (inspect.isroutine(a)))
    return [attr for attr in attributes if not (attr[0].startswith('__') and attr[0].endswith('__'))][1]

But usage gives me this error umongo.exceptions.NoDBDefinedError: init must be called to define a db

Usage: properties=get_class_properties(Todo)

UPD Here is my mongo initialization code:

async def mongo_client(app):
    conf = app["config"]["mongo"]
    client = AsyncIOMotorClient(host=conf["host"], port=conf["port"])
    db = client[conf["db"]]
    instance.init(db)
    await Todo.ensure_indexes()
    app["db_client"]: AsyncIOMotorClient = client
    app["db"] = db
    yield
    await app["db_client"].close()

Solution

  • The trick was that

    properties=get_class_properties(Todo)

    invokes earlier than

    async def mongo_client(app):

    Solution is use things in right order (see comments to code)

    async def init_app(argv=None):
        app = web.Application(middlewares=[deserializer_middleware], logger=logger)
        app["config"] = config
    
        conf = app["config"]["mongo"]
        client = AsyncIOMotorClient(host=conf["host"], port=conf["port"])
        db = client[conf["db"]]
        instance.init(db)
        # Remove this line:
        # app.cleanup_ctx.append(mongo_client)
        app.cleanup_ctx.append(api_client)
    
        register_routes(app)
        return app
    
    def register_routes(app: web.Application):
        # Use here:
        todo_resource = RestResource(
            entity='todo',
            factory=Todo,
            properties=get_class_properties(Todo)
        )
        todo_resource.register(app.router)