2

I'm making migrations in Flask using unsurprisingly Flask-Migrate. once I execute python manage.py db init it creates directory migrations with initial migrations file. Then I execute python manage.py db migrate and I get this:

...
...
target_metadata = current_app.extensions['migrate'].db.metadata
AttributeError: 'NoneType' object has no attribute 'metadata'

I understand from this output that 'migrate' is None hence I'm getting an attribute error.

models.py:

from sqlalchemy.sql import func
from project import db, bcrypt


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(128), nullable=False, unique=True)
    email = db.Column(db.String(128), nullable=False, unique=True)
    password = db.Column(db.String(255), nullable=False)
    active = db.Column(db.Boolean(), default=True, nullable=False)
    created_date = db.Column(db.DateTime, default=func.now(), nullable=False)

    def __init__(self, username, email, password):
        self.username = username
        self.email = email
        self.password = bcrypt.generate_password_hash(password).decode()

    def to_json(self):
        return {
            'id': self.id,
            'username': self.username,
            'email': self.email,
            'active': self.active,
        }

The question is why nothing is being passed to it ? I'm following a tutorial and I'm not supposed to have this error.

I've got this from similar topic:

NoneType means that instead of an instance of whatever Class or Object you think you're working with, you've actually got None. That usually means that an assignment or function call up above failed or returned an unexpected result.

this is what I've found in env.py file in the migrations directory:

from flask import current_app
config.set_main_option('sqlalchemy.url',
                       current_app.config.get('SQLALCHEMY_DATABASE_URI'))
target_metadata = current_app.extensions['migrate'].db.metadata

current_app is being imported from Flask but doesn't contain the extension migrate from which I need to use the metadata.

There's no reason for it to be throwing None though because the extension is correctly initilised in __init__.py file:

...
...
from flask_migrate import Migrate

db = SQLAlchemy()
toolbar = DebugToolbarExtension()
cors = CORS()
migrate = Migrate()
bcrypt = Bcrypt()

def create_app(script_info=None):
    app = Flask(__name__)
    app_settings = os.getenv('APP_SETTINGS')
    app.config.from_object(app_settings)
    app.config.from_object('project.config.DevelopmentConfig')
    toolbar.init_app(app)
    cors.init_app(app)
    db.init_app(app)
    migrate.init_app(app)     #  <--
    bcrypt.init_app(app)

    from project.api.users import users_blueprint
    app.register_blueprint(users_blueprint)

    @app.shell_context_processor
    def ctx():
        return {'app': app, 'db': db}

    return app
Mark
  • 161
  • 11

1 Answers1

10

I had a missing argument in the initialization of the migrate extension. Migrate takes in the app instance and the instance of db.

def create_app(script_info=None):
    app = Flask(__name__)
    app_settings = os.getenv('APP_SETTINGS')
    app.config.from_object(app_settings)
    app.config.from_object('project.config.DevelopmentConfig')
    toolbar.init_app(app)
    cors.init_app(app)
    db.init_app(app)
    migrate.init_app(app, db)     #  <--
    bcrypt.init_app(app)

    from project.api.users import users_blueprint
    app.register_blueprint(users_blueprint)

    @app.shell_context_processor
    def ctx():
        return {'app': app, 'db': db}

    return app
Mark
  • 161
  • 11