Search code examples
pythonmongodbodmumongo

How to separate umongo's object document models from the main web app or how to avoid calling @instance.register where document models are defined?


While creating a web app using Flask or FastAPI, there would be a main.py file that basically instantiates and runs everything. I think that is also the right place for the database connections and initialization. So ideally I'd like to have a separate model.py file that basically just has the object document mapping definitions and nothing else.

Is it possible to do something like that in umongo?

I mean we need to call @instance.register above every object document map class. But if that is in a separate file and the DB is not initialized there, then in that file there are no instances. The instance would be declared in the main.py file.

For example, when you use Tortoise, it allows you to pass the whole model.py file as a module and register it with FastAPI like the following -

register_tortoise(
    app,
    db_url=os.environ.get("DATABASE_URL"),
    modules={"models": ["models.model"]}, #model -> model.py which has all the class definitions
    generate_schemas=True
)

For demo, you can have the following as model.py file contents -

from umongo import Document
from umongo.fields import StringField, URLField, DateTimeField
from datetime import datetime

class WebData(Document):
    url = URLField()
    summary = StringField()
    created_at = DateTimeField(missing=datetime.now)

    def __str__(self):
        return self.url

And the following main.py file that uses FastAPI -

from fastapi import FastAPI
from pymongo import MongoClient
from umongo import Instance

#db = MongoClient().test
#instance = Instance(db)

app = FastAPI()

@app.get('/ping')
async def pong():
    return {'ping': 'pong'}


if __name__ == "__main__":
    import uvicorn
    uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)

Solution

  • You can instantiate the instance at import but pass it a DB connection at app init.

    common.py

    from umongo.frameworks import PyMongoInstance
    
    
    instance = PyMongoInstance()
    

    model.py

    from umongo import Document
    
    from .common import instance
    
    
    @instance.register
    class MyDocument(Document)
    

    init.py

    from .common import .instance
    import .model
    
    
    def create_app():
        database = MongoClient().test
        instance.init(database)
        ...
    

    (Note: in umongo 3 beta, instance.init is renamed to instance.set_db.)