Search code examples
flaskflask-mongoengine

Accessing the properties of the mongoengine instance in a Flask app


I've registered the flask-mongoengine extension in my Flask app and initialized it.

I now want to access its conn property as I want to do pure MongoDB queries too.

>> app.extensions
{'csrf': <flask_wtf.csrf.CSRFProtect object at 0x00000213B72AB940>,
 'mail': <flask_mail._Mail object at 0x00000213B72ABCF8>,
 'mongoengine': {
     <flask_mongoengine.MongoEngine object at 0x00000213B72ABDD8>: {
         'app': <Flask 'app'>,
         'conn': MongoClient(host=['xxx'], document_class=dict, tz_aware=False, connect=True, ssl=True, replicaset='Cluster0-shard-0', authsource='admin', retrywrites=True, read_preference=Primary())
     }
  },
  'rq2': <flask_rq2.app.RQ object at 0x00000213B5DE8940>,
  'security': <flask_security.core._SecurityState object at 0x00000213B734EE10>
}

Is there a way to access the conn property other than the very convoluted (and error-prone):

>> list(app.extensions.get('mongoengine').values())[0].get('conn')
MongoClient(host=['xxx'], document_class=dict, tz_aware=False, connect=True, ssl=True, replicaset='Cluster0-shard-0', authsource='admin', retrywrites=True, read_preference=Primary())

Does flask-mongoengine have a method to access its properties?


Solution

  • The MongoEngine instance has a connection attribute, use that.

    You don't need to use app.extensions; that's more of an internal data structure for extensions to keep track of their own state when they need to access this from the current app context.

    In your own code, just keep a reference to the MongoEngine instance you created. The documentation uses:

    db = MongoEngine(app)
    

    or

    db = MongoEngine()
    # in an app factory, attach to an app with db.init_app(app)
    

    and so you can use:

    db.connection
    

    Next, there is also a current_mongoengine_instance() utility function that essentially gives you the same object as what your code already achieved. Use it like this:

    from flask_mongoengine import current_mongoengine_instance
    
    current_mongoengine_instance().connection
    

    As a side note: the way this extension uses app.extensions is ... over-engineered and redundant. The rationale in the source code is:

    # Store objects in application instance so that multiple apps do not
    # end up accessing the same objects.
    

    but multiple apps already have separate app.extensions dictionaries. While this method does let you use multiple mongoengine connections, you still then can't use this data structure to distinguish between different connections with only the current app context. The implementation for current_mongoengine_instance() only further illustrates that the extension doesn't have a proper strategy for handling multiple connections. You just get the 'first' one, whatever that may mean in the context of unordered dictionaries. The Flask SQLAlchemy extension instead uses a single extension instance to manage multiple connections via a system called binds.