Search code examples
pythonflaskmodelflask-restful

Flask Application Circular Dependencies


I am developing a Flask application, and I am not sure why I am getting this error:

  File "app.py", line 17, in <module>
    from endpoints.users.resource import UserResource
  File "{basedir}/endpoints/users/resource.py", line 4, in <module>
    from .model import User
  File "{basedir}/endpoints/users/model.py", line 1, in <module>
    from app import db
  File "{basedir}/app.py", line 17, in <module>
    from endpoints.users.resource import UserResource
ImportError: cannot import name 'UserResource' from 'endpoints.users.resource' ({basedir}/endpoints/users/resource.py)

I believe it is due to a circular dependency, from looking at the error, but I can't figure out why, because I think that the order in which I am importing things in my code should have circumvented this issue:

app.py:

from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config.from_object(Config)
db = SQLAlchemy(app)

api = Api(app)
api.prefix = '/api'

from endpoints.users.resource import UserResource

api.add_resource(UserResource, '/users')
 
if __name__ == '__main__':
    app.run(host="0.0.0.0")

endpoints/users/model.py:

from app import db

class User(db.Model):
    # info about the class, requires db

endpoints/users/resource.py:

from flask_restful import Resource
from .model import User
from app import db

class UserResource(Resource):
    def get(self, username=None):
        # get request, requires db and User

In app.py, since I am importing from endpoints.users.resource after db is created, shouldn't that circumvent the circular dependency?

In addition, I can run this with flask run but when I try to use python app.py, then it gives me the above error. Why would these give different results?


Solution

  • So on from endpoints.users.resource import UserResource line python tries to import from app import db line to app.py which causes app reference to itself, which is not good at all.

    One workaround to solve circual import errors in Flask is using init_app function which exists in most of Flask apps. So just create database file like this:

    database.py

    from flask_sqlalchemy import SQLAlchemy
    db = SQLAlchemy()
    

    app.py

    from flask import Flask
    from flask_restful import Api
    from database import db
    from endpoints.users.resource import UserResource
    
    app = Flask(__name__)
    
    app.config.from_object(Config)
    db.init_app(app)
    
    api = Api(app)
    api.prefix = '/api'
    
    
    
    api.add_resource(UserResource, '/users')
     
    if __name__ == '__main__':
        app.run(host="0.0.0.0")
    

    endpoints/users/model.py:

    from database import db
    
    class User(db.Model):
        # info about the class, requires db
    

    endpoints/users/resource.py:

    from flask_restful import Resource
    from endpoints.users.model import User
    from database import db
    
    class UserResource(Resource):
        def get(self, username=None):
            # get request, requires db and User
    

    Note that I rewrote your imports from related, so don't forget to add __init__.py files
    Your structure will be like this:

    .
    ├── app.py
    └── database.py/
    └── endpoints/
            ├── __init__.py
            └── users/
                ├── __init__.py
                ├── model.py
                └── resource.py