0

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()
Skufler
  • 187
  • 1
  • 4
  • 14

2 Answers2

0

This is a copy/paste of this answer from the author of this library:

As far as I remeber, this exception raises when you're trying to use lazy clients without initializing them properly. Any lazy class of uMongo expects that the used database will be specified before the usage. Everything that you need is to specify the used database and invoke the init method of your lazy instance, like this:

from motor.motor_asyncio import AsyncIOMotorClient
from umongo import MotorAsyncIOInstance

client = AsyncIOMotorClient("mongodb://user:password@host:port/")
client = client["test_database"]
lazy_umongo = MotorAsyncIOInstance()
lazy_umongo.init(client)

As an example you can look into Auth/Auth microservice code, where documents defined and store in the separate files from the actual usage. Also these files with code as examples (documents.py and prepare_mongodb.py) will help you to find a solution.

Leogout
  • 1,187
  • 1
  • 13
  • 32
0

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)
Skufler
  • 187
  • 1
  • 4
  • 14