Question

I have the following models in file listpull/models.py:

from datetime import datetime

from listpull import db


class Job(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    list_type_id = db.Column(db.Integer, db.ForeignKey('list_type.id'),
                             nullable=False)
    list_type = db.relationship('ListType',
                                backref=db.backref('jobs', lazy='dynamic'))
    record_count = db.Column(db.Integer, nullable=False)
    status = db.Column(db.Integer, nullable=False)
    sf_job_id = db.Column(db.Integer, nullable=False)
    created_at = db.Column(db.DateTime, nullable=False)
    compressed_csv = db.Column(db.LargeBinary)

    def __init__(self, list_type, created_at=None):
        self.list_type = list_type
        if created_at is None:
            created_at = datetime.utcnow()
        self.created_at = created_at

    def __repr__(self):
        return '<Job {}>'.format(self.id)


class ListType(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True, nullable=False)

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return '<ListType {}>'.format(self.name)

I call ./run.py init then ./run.py migrate then ./run.py upgrade, and I see the migration file generated, but its empty:

"""empty message

Revision ID: 5048d48b21de
Revises: None
Create Date: 2013-10-11 13:25:43.131937

"""

# revision identifiers, used by Alembic.
revision = '5048d48b21de'
down_revision = None

from alembic import op
import sqlalchemy as sa


def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    pass
    ### end Alembic commands ###


def downgrade():
    ### commands auto generated by Alembic - please adjust! ###
    pass
    ### end Alembic commands ###

run.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from listpull import manager
manager.run()

listpull/__init__.py

# -*- coding: utf-8 -*-
# pylint: disable-msg=C0103

""" listpull module """

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
from mom.client import SQLClient
from smartfocus.restclient import RESTClient


app = Flask(__name__)
app.config.from_object('config')

db = SQLAlchemy(app)

migrate = Migrate(app, db)

manager = Manager(app)
manager.add_command('db', MigrateCommand)

mom = SQLClient(app.config['MOM_HOST'],
                app.config['MOM_USER'],
                app.config['MOM_PASSWORD'],
                app.config['MOM_DB'])

sf = RESTClient(app.config['SMARTFOCUS_URL'],
                app.config['SMARTFOCUS_LOGIN'],
                app.config['SMARTFOCUS_PASSWORD'],
                app.config['SMARTFOCUS_KEY'])

import listpull.models
import listpull.views

UPDATE

If I run the shell via ./run.py shell and then do from listpull import * and call db.create_all(), I get the schema:

mark.richman@MBP:~/code/nhs-listpull$ sqlite3 app.db 
-- Loading resources from /Users/mark.richman/.sqliterc
SQLite version 3.7.12 2012-04-03 19:43:07
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .schema
CREATE TABLE job (
    id INTEGER NOT NULL, 
    list_type_id INTEGER NOT NULL, 
    record_count INTEGER NOT NULL, 
    status INTEGER NOT NULL, 
    sf_job_id INTEGER NOT NULL, 
    created_at DATETIME NOT NULL, 
    compressed_csv BLOB, 
    PRIMARY KEY (id), 
    FOREIGN KEY(list_type_id) REFERENCES list_type (id)
);
CREATE TABLE list_type (
    id INTEGER NOT NULL, 
    name VARCHAR(80) NOT NULL, 
    PRIMARY KEY (id), 
    UNIQUE (name)
);
sqlite> 

Unfortunately, the migrations still do not work.

Was it helpful?

Solution 2

When you call the migrate command Flask-Migrate (or actually Alembic underneath it) will look at your models.py and compare that to what's actually in your database.

The fact that you've got an empty migration script suggests you have updated your database to match your model through another method that is outside of Flask-Migrate's control, maybe by calling Flask-SQLAlchemy's db.create_all().

If you don't have any valuable data in your database, then open a Python shell and call db.drop_all() to empty it, then try the auto migration again.

UPDATE: I installed your project here and confirmed that migrations are working fine for me:

(venv)[miguel@miguel-linux nhs-listpull]$ ./run.py db init
  Creating directory /home/miguel/tmp/mark/nhs-listpull/migrations...done
  Creating directory /home/miguel/tmp/mark/nhs-listpull/migrations/versions...done
  Generating /home/miguel/tmp/mark/nhs-listpull/migrations/script.py.mako...done
  Generating /home/miguel/tmp/mark/nhs-listpull/migrations/env.pyc...done
  Generating /home/miguel/tmp/mark/nhs-listpull/migrations/env.py...done
  Generating /home/miguel/tmp/mark/nhs-listpull/migrations/README...done
  Generating /home/miguel/tmp/mark/nhs-listpull/migrations/alembic.ini...done
  Please edit configuration/connection/logging settings in
  '/home/miguel/tmp/mark/nhs-listpull/migrations/alembic.ini' before
  proceeding.
(venv)[miguel@miguel-linux nhs-listpull]$ ./run.py db migrate
INFO  [alembic.migration] Context impl SQLiteImpl.
INFO  [alembic.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate] Detected added table 'list_type'
INFO  [alembic.autogenerate] Detected added table 'job'
  Generating /home/miguel/tmp/mark/nhs-
  listpull/migrations/versions/48ff3456cfd3_.py...done

Try a fresh checkout, I think your setup is correct.

OTHER TIPS

Ensure to import the Models in the manage.py file (or the file with the migrate instance). You have to import the models in the file, even if you are not explicitly using them. Alembic needs these imports to migrate, and to create the tables in the database. For example:

# ... some imports ...
from api.models import User, Bucketlist, BucketlistItem # Import the models

app = create_app('dev')
manager = Manager(app)
migrate = Migrate(app, db)

manager.add_command('db', MigrateCommand)

# ... some more code here ...

if __name__ == "__main__":
    manager.run()
    db.create_all()

I had the same issue but a different problem caused it. Flask-migrate workflow consists of two consequent commands:

flask db migrate

which generates the migration and

flask db upgrade

which applies the migration. I forgot to run the last one and tried to start next migration without applying the previous one.

For anyone coming who comes across this, my problem was having

db.create_all()

in my main flask application file which created the new table without the knowledge of alembic

Simply comment it out or delete it altogether so it doesn't mess with future migrations.

but unlike @Miguel's suggestion, instead of dropping the whole database (i had important information in it), i was able to fix it by deleting the new table created by Flask SQLAlchemy and then running the migration.

and this time alembic detected the new table and created a proper migration script

I just encountered a similar problem. I'd like to share my solution for anyone else encountering this thread. For me, I had my models in a package. For example models/user.py and I tried from app.models import * which did not detect anything on the migrate. However, if I changed the import to from app.models import user this is okay why my project is young, but as I have more models a bulk import would be preferable.

Strange solve for me is: delete database and folder migrations. Then

>>> from app import db
>>> db.create_all()

After flask db init or python app.py db init and then flask db migrate or python app.py db migrate. Wow, It's strange, but it works for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top