0

Hello I have the following folder structure

    .
    ├── api
    │   ├── users
    │   │   ├── __init__.py
    │   │   ├── model.py
    │   │   └── routes.py
│   ├── |__init__.py
    ├── __init__.py
    ├── requirements.txt
    └── server.py

In api.__init__.py I have the following code:

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

db = SQLAlchemy()


def create_app(env):
    app = Flask(__name__)
    db.init_app(app)
    api = Api(app)
    users.register_routes(api)
    return app

and in users/model.py I have the following code:

from sqlalchemy import Column, Integer, String
from .. import db

class User(db.Model):
    __tablename__ = 'users'
...

And in server.py I have the following code:

import os

from api import create_app

app = create_app(os.getenv("ENV"))
if __name__ == "__main__":
    app.run(port=os.getenv("PORT"), debug=os.getenv("DEBUG")=='True')

The problem is that when I execute server.py I have the following error:

AttributeError: module 'api.db' has no attribute 'Model'

How can I solve this error?

Thanks

3
  • Are you sure db is not overridden inside api/__init__.py ? try to confirm it with a quick print(db) right after from .. import db. Attaching the full exception will be helpful too. Commented Jul 5, 2020 at 10:44
  • The print return the following: <module 'api.db' (namespace)>, updated with all code of api.__init__ Commented Jul 5, 2020 at 10:50
  • That's not right, i think it should be <SQLAlchemy engine=None> so my guess it's overridden with something else. Probably you have a api/db.py ? Commented Jul 5, 2020 at 10:55

1 Answer 1

1

i would suggest you making some changes to the structure of your project to avoid circular import issue and prefer importing your app as package not as a module and also as a good practice __init __.py is kept just for import and some metadata like __author__ and __version__

api

  .. errors (blueprint)
    .. __init__.py
    .. routes.py


  .. users (blueprint)
    .. __init__.py
    .. model.py
    .. routes.py

  .. extensions.py

  .. __init__.py
  .. app.py (here where your define "create_app()" function)


server.py
requirements.txt

in api/users/__init __.py:

from .routes import bp

in api/users/models.py:

from api.extensions import db

# from sqlalchemy import Column, Integer, String  # You don't need this since you already imported the db oject 

class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)  # here 
...

in api/users/routes.py:

from flask import Blueprint, request, jsonify ..

from api.extensions import db  # maybe you need it here
from .models import User  # Your model


bp = Blueprint('users', __name__)  # instantiate your 'users' Blueprint


@bp.route('/', methods=['GET', 'POST']) 
def index():

    ..
    
    return jsonify(..)

in /api/extensions.py, define the Flask extensions needed for your app

from flask_sqlalchemy import SQLAlchemy
..

db = SQLAlchemy()
..

in /api/__init __.py:

from .app import create_app

in /api/app.py:

from flask import Flask
..

def create_app(config_object):
    """Create a Flask application using the app factory pattern."""

    app = Flask(__name__)

    """Load configuration."""
    # app.config.from_object(CONFIGS[config_object])  # an example 

..

    """Init app extensions."""
    from .extensions import db
    db.init_app(app)

..

    """Register blueprints."""
    from .errors import bp as errors_bp
    app.register_blueprint(errors_bp)

    from .users import bp as users_bp
    app.register_blueprint(users_bp, url_prefix='/users')

..
    
    return app

in /server.py:

import os

from api import create_app


app = create_app(os.getenv("ENV", "development"))

if __name__ == "__main__":
    app.run(port=os.getenv("PORT", 5000), debug=os.getenv("DEBUG", True)
Sign up to request clarification or add additional context in comments.

3 Comments

Great answer, can you tell me where I did circular imports?
i just mean, since flask is un-opinionated framework, with good project structure you can avoid many issues (circular imports - not your case - ), make your app maintainable and easy to debug and extensible.
if you want to register routes just prefer @bp.route() decorator in users/routes.py or at the bottom of users/routes.py you can call bp.add_url_rule('/', 'index', index)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.