Flask-Migrate No Changes Detected to Schema on first migration
Asked Answered
C

12

27

I'm using Flask with Flask-SQLAlchemy and Flask-Migrate to create an application, however when I try to create a migration nothing happens.

I've created two tables in app/models.py:

from flask import current_app
from . import db

class Student(db.Model):
    __tablename__ = 'students'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, nullable=False)
    password_hash = db.Column(db.String(128))

    def __init__(self, **kwargs):
        super(Student, self).__init__(**kwargs)

    def __repr__(self):
        return '<Tutor {}>' % self.id

class Tutor(db.Model):
    __tablename__ = 'tutors'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))

    def __init__(self, **kwargs):
        super(Tutor, self).__init__(**kwargs)
    def __repr__(self):
        return '<Student %r>' % self.id

Then I also have app/__init__.py with the following code:

from flask import Flask
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

#from .models import User, Task, Project, UserProject

from config import config

bootstrap = Bootstrap()
db = SQLAlchemy()
migrate = Migrate()

def create_app(config_name='default'):
    #print config_name.name
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    bootstrap.init_app(app)
    db.init_app(app)
    migrate.init_app(app, db)

    ## Register the main blueprint for main app functionality
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app

and app.py:

import os
from app import create_app, db
from app.models import Tutor, Student

app = create_app('default')

@app.shell_context_processor
def make_shell_context():
    return dict(db=db, Tutor=Tutor, Student=Student)

I can run flask db init with no problem and it creates the migrations directory and all necessary files with the following output:

Creating directory /Users/Jasmine/projects/flask/flask-tutoring/migrations ... done
Creating directory /Users/Jasmine/projects/flask/flask-tutoring/migrations/versions ... done
Generating /Users/Jasmine/projects/flask/flask-tutoring/migrations/script.py.mako ... done
Generating /Users/Jasmine/projects/flask/flask-tutoring/migrations/env.py ... done
Generating /Users/Jasmine/projects/flask/flask-tutoring/migrations/README ... done
Generating /Users/Jasmine/projects/flask/flask-tutoring/migrations/alembic.ini ... done
Please edit configuration/connection/logging settings in '/Users/Jasmine/projects/flask/flask-tutoring/migrations/alembic.ini' before proceeding.

but when I try and run flask db migrate alembic can't detect that I've got tables in app/models.py. I get the following output:

INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.env] No changes in schema detected.

There is no migration script created, its as though models.py doesn't exist.

Apologies if this is a repeated question, but I can't find another example where its the first migration that fails and no migration script at all is created.

I've tried checking if there is already a table created somewhere by running db.drop_all() in the shell but that doesn't seem to be the problem.

UPDATE

I figured out a way to solve this on my own but would like a better understanding of why this worked.

I re-named app.py to flasktutor.py and re-ran export FLASK_APP='flasktutor.py'. Subsequently the migration worked perfectly.

Please could someone explain why when the file was called app.py and I used export FLASK_APP='app.py' the migration did not register changes to the schema.

Condone answered 10/8, 2018 at 9:27 Comment(3)
There's got to be something else that you changed. I have an application called app.py that I use to test Flask-Migrate and that works perfectly well. If you have a complete example that shows this problem it would be useful if you can share it.Misrepresent
I have the same problem but my file's name is run.py. I changed it to app.py then to phoenix.py and still the same issue. Debugging the application on this line app.config.from_object(app_config[config_name]) I uncovered that the reference to config_name is throwing the same error when I run the app. KeyError: <flask.cli.ScriptInfo object at 0x0000000003A11D68>.Sluiter
This was an issue I had, thanks for this, it is to do with flask mixing up a package and a module import of the same name at different pointsVaquero
I
26

I encountered this problem and solved it by importing my models at env.py in the migrations folder right after the following comments

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata

from app.models import Student, Tutor
Izawa answered 4/12, 2019 at 20:38 Comment(1)
I added the same import but in top of fileAnticlockwise
C
19

Pls make sure that you already import your models (Tutor, Student, ...) before your migrate.init_app(app, db)

Ching answered 5/9, 2018 at 9:34 Comment(1)
This simply saved my time.Looseleaf
V
12

This is how I solved the problem in my case:

  1. Import the Migrate model: from flask_migrate import Migrate
  2. Initiate Migrate class: migrate = Migrate(app, db)
  3. Comment db.create_all()
  4. Drop your database now => DROP DATABASE db_name;
  5. Create it again => CREATE DATABSE db_name OWNER owner_name;
  6. Export you flask entry file => export FLASK_APP=name_app.py
  7. Run flask db migrate

Note: The 6th step should be used in case you get this error:

Error: Could not locate a Flask application

Hope this will help someone.

Vacuva answered 30/1, 2020 at 13:6 Comment(1)
Thansk for actually telling I had to comment db.create_all().Gig
S
11

I just ran into the same issue, following Miguel's great tutorial, and the hints here were very helpful!

My solution - which doesn't require "hacking" env.py - is to simply add

from app import models

to __init__.py.

If you have a different project layout you might need to adapt the import but it seems like you need to make sure that models gets imported properly for flask db migrate to work.

Sindysine answered 2/3, 2021 at 16:14 Comment(2)
Perfect! "Imports" were the culprits here. Did not import models before instantiating the Migrate() earlier.Chicken
I was following the same (amazing) tutorial. I'd changed the module name to "bloggy" in order to disambiguate app. So my import is from bloggy import models and viola table has been created.Parhelion
F
6

Well, I encountered the same problem following Miguel Grinberg tutorial.

Previously I created the tables using the shell calling

db.create_all()

So, I thougth to drop the tables

db.drop_all()

and trying the migrate command again, it worked as expected:

Roberto@MyPC MINGW64 /e/Projects/Flask/flasky ((5c))
$ flask db migrate -m "initial migration - Role Users"
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'roles'
INFO  [alembic.autogenerate.compare] Detected added table 'users'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_users_username' on '['username']'
Generating E:\Projects\Flask\flasky\migrations\versions\4de323c9c089_initial_migration_role_users.py ... done

After that, I used flask-migrate to re-create the tables

$ flask db upgrade
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> b641ee80a60d, initial migration - Role Users
Fiat answered 14/8, 2019 at 10:57 Comment(0)
R
3

The flask-migrate works after you change your table schema.

Such as, before:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy(app)

class Test(db.Model):
    content = db.Column(db.String(60))

and then you change your Test schema, like:

class Test(db.Model):
    content = db.Column(db.String(60))
    add = db.Column(db.String(60))

Now, you can use flask db migrate -m "migrate test" to work.

You will get migrate version information.

Realpolitik answered 24/9, 2020 at 4:26 Comment(0)
K
2

I encountered the same problem following Miguel Grinberg tutorial. I solved this my adding

from app.models import  User, Post

to migrations/env.py

Keister answered 15/7, 2020 at 22:5 Comment(1)
then re run flask db migrate -m "users table"Keister
D
2

This worked for me:

In migrations/env.py, import your models

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from app.models import * # <= Add this line
from flask import current_app
Dobson answered 9/11, 2020 at 11:2 Comment(0)
E
0

You can point to empty database only to create migration file, then return back to upgrade your real database.

Eyestalk answered 26/11, 2020 at 13:53 Comment(0)
D
0

After some time trying to fix it and reading about it, I just deleted the migrations directory (folder) and the app.db. Then ran again:

  1. "flask db init"
  2. "flask db migrate"
  3. "flask db upgrade"

This re-generate the directories and all working fine now.

If you want to improve your migration script, this link to an upgrade from Miguel, can be useful: https://www.youtube.com/watch?v=wpRVZFwsD70&feature=emb_logo

Durkin answered 26/2, 2021 at 0:8 Comment(0)
B
0

So I don't know about everyone else; but, none of these fully worked for me. There is one extra step that did though. (Perhaps it's because I'm using sqlite database).

What I did from app dir:

cd instance
rm site.db (sqlite3 database file)
   (note: yours might be different based on your configuration file)
   (but it will likely be the only file in there)
cd ..
rm -rf migrations
flask db init
flask db migrate -m "initial commit"
flask upgrade
Brightness answered 20/2 at 0:24 Comment(0)
S
0

as others have said, add before migrations are initialized. I'm adding another case for migration initialization via constructor:

from app.models import * # first, before initializing migration
migrate = Migrate(app, db)
Sourwood answered 21/3 at 17:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.