pythonflaskflask-restplusflask-pymongo

How to share a flask-pymongo instance in the api routes handler


I am trying to design a simple api using flask, flask-restplus, and flask-pymongo but I'm facing one structural design, based on import and variables sharing, I cannot get access to the db in any way.

Here is my code in my main engine file:

app = Flask(__name__)
db = PyMongo(app)

api = Api(app)

from auth import namespace as ns1
api.add_namespace(registerNamespace.api)


if __name__ == '__main__':
     api.run()

But at the same time, I would like to get access to the db instance in actual api implementation:

from engine import engine

api = Namespace('register', description="Registration")

db = engine.db

@api.route('/whatever')
Class Whatever():
 def get(self):
    db.doSomething();
    return "Simple getter"

I get the following error.

ImportError: cannot import name engine

I've been trying to fix this in quite a long time, because I don't think it is that stupid of a structural decision but I probably am wrong. Which ways, either structural or import wise could help fixing this?

Thank you in advance!


Solution

  • There is myriad of approaches to architect your flask application for easy resource sharing. I however favor binding resources to a common package usually the application package such that other modules can import resources from that package.

    Say we have a fictitious project named demo with the following structure:

    .
    ├── api
    │   ├── __init__.py
    │   └── namespace1.py
    └── demo
        ├── __init__.py
        ├── main.py
        └── setup.py
    

    Notice that we have api separate as its own package.

    Here is a brief description of the contents of individual module.

    demo/__init__.py

    db = None # initials package level name to None. 
    

    demo/setup.py

    from flask import Flask
    from flask_pymongo import PyMongo
    
    import demo
    
    app = Flask('demo')
    demo.db = PyMongo(app)  # Here is where we bind the shared resource to the package level name.
    

    demo/main.py

    from demo.setup import app
    from api import register_api
    
    register_api(app)
    
    if __name__ == '__main__':
         app.run()
    

    Our API can import from demo easily:

    api/namespace1.py

    from flask_restplus import Namespace, Resource, fields
    
    from demo import db  # Look ma!, it's easy to share resources.
    ...
    
    @ns.route('/')
    class CatList(Resource):
        @ns.doc('list_cats')
        @ns.marshal_list_with(cat)
        def get(self):
            '''List all cats'''
            print(db)
            return CATS
    

    You can view the complete sample here.