Search code examples
pythonflask-sqlalchemy

flask sqlalchemy with circular imports with db models


Here is my app structure:

backend
├── erp
│   ├── blueprint_create_order_and_add_products
│   │   ├── __init__.py
│   │   └── resources
│   │       ├── create_order.py
│   │       ├── __init__.py
│   ├── blueprint_general_query
│   │   ├── __init__.py
│   │   └── resources
│   │       ├── general_query.py
│   │       └── __init__.py
│   ├── common
│   │   ├── __init__.py
│   │   └── models
│   │       ├── brand.py
│   │       ├── productwithspecs.py
│   ├── database_collection
│   │   ├── finance.db
│   │   ├── orders.db
│   │   └── vendors.db
│   └── __init__.py
├── __init__.py
└── run.py

The models folder have db classes, the problem is that the class in brand module involves (through relationship) and imports the class in productwithspecs module, and there are lots of related db classes. How to import them in a CRUD resource of flask restful without circular imports?

The code of app.py is:

from erp import app

if __name__ == '__main__':
    app.run(debug=True)

The code of erp/__ini__.py is:

from flask import Flask 
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
app = Flask(__name__)

app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:////tmp/test.db"

db = SQLAlchemy(app)
ma = Marshmallow(app)

# api_createorders_addproducts
from erp.blueprint_create_order_and_add_products import bp as bp1 

# REGISTER blueprint apis to app
app.register_blueprint(bp1)

Please let me know how to avoid circular imports, as I will be needing to import db classes into resources folder in blueprints e.g create_order module etc.


Solution

  • You should use an Application Factory App. You find the official recommendation here and this is a good tutorial.

    After refactoring your erp/__init__.py should look similar to:

    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_marshmallow import Marshmallow
    app = Flask(__name__)
    
    db = SQLAlchemy(app)
    ma = Marshmallow(app)
    
    def create_app():
        db.init_app(app)
        app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:////tmp/test.db"
        ma.init_app(app)
    
        with app.app_context():
            # Include your routes here
    
            app.register_blueprint(erp.blueprint_create_order_and_add_products.bp)
    
        return app
    

    Your app.py:

    from erp import create_app
    
    app = create_app()
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    And from all other modules you can import like this:

    from erp import app, db