Alembic - 自发生成空迁移

day*_*mer 19 python migration flask flask-sqlalchemy alembic

我试图Alembic第一次使用,并希望使用此处--autogenerate描述的功能

我的项目结构看起来像

project/
       configuration/
                    __init__.py
                    dev.py
                    test.py
       core/
           app/
              models/
                    __init__.py
                    user.py
       db/
          alembic/
                  versions/
                  env.py
          alembic.ini
Run Code Online (Sandbox Code Playgroud)

我使用Flask,并SQLAlchemy和他们的Flask-SQLAlchemy扩展.我的模特User看起来像

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    # noinspection PyShadowingBuiltins
    uuid = Column('uuid', GUID(), default=uuid.uuid4, primary_key=True,
                  unique=True)
    email = Column('email', String, nullable=False, unique=True)
    _password = Column('password', String, nullable=False)
    created_on = Column('created_on', sa.types.DateTime(timezone=True),
                        default=datetime.utcnow())
    last_login = Column('last_login', sa.types.DateTime(timezone=True),
                        onupdate=datetime.utcnow())
Run Code Online (Sandbox Code Playgroud)

如上所述这里,我修改env.py的样子

from configuration import app

alembic_config = config.get_section(config.config_ini_section)
alembic_config['sqlalchemy.url'] = app.config['SQLALCHEMY_DATABASE_URI']
engine = engine_from_config(
    alembic_config,
            prefix='sqlalchemy.',
            poolclass=pool.NullPool)
Run Code Online (Sandbox Code Playgroud)

from configuration import db


target_metadata = db.metadata
Run Code Online (Sandbox Code Playgroud)

这里configuration.__init__py看起来像

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
import dev


app = Flask(__name__)
app.config.from_envvar('SETTINGS_PT')
db = SQLAlchemy(app)
Run Code Online (Sandbox Code Playgroud)

现在我运行迁移

$alembic revision --autogenerate -m "Added user table"
INFO  [alembic.migration] Context impl PostgresqlImpl.
INFO  [alembic.migration] Will assume transactional DDL.
  Generating /Users/me/IdeaProjects/project/db/alembic/versions/55a9d5
  35d8ae_added_user_table.py...done
Run Code Online (Sandbox Code Playgroud)

但文件alembic/versions/55a9d5有空upgrade()downgrade()方法

"""Added user table

Revision ID: 1b62a62eef0d
Revises: None
Create Date: 2013-03-27 06:37:08.314177

"""

# revision identifiers, used by Alembic.
revision = '1b62a62eef0d'
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 Code Online (Sandbox Code Playgroud)

为什么它不能理解有一个新的User模型?请帮忙

day*_*mer 21

根据@zzzeek,在我将以下内容包括在内后env.py,我能够使用--autogenerate选项

env.py下面run_migrations_online()

from configuration import app
from core.expense.models import user # added my model here

alembic_config = config.get_section(config.config_ini_section)
alembic_config['sqlalchemy.url'] = app.config['SQLALCHEMY_DATABASE_URI']
engine = engine_from_config(
    alembic_config,
    prefix='sqlalchemy.',
    poolclass=pool.NullPool)
Run Code Online (Sandbox Code Playgroud)

然后我跑了alembic revision --autogenerate -m "Added initial table",得到了

def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.create_table('users',
    sa.Column('uuid', sa.GUID(), nullable=False),
    sa.Column('email', sa.String(), nullable=False),
    sa.Column('password', sa.String(), nullable=False),
    sa.Column('created_on', sa.DateTime(timezone=True), nullable=True),
    sa.Column('last_login', sa.DateTime(timezone=True), nullable=True),
    sa.PrimaryKeyConstraint('uuid'),
    sa.UniqueConstraint('email'),
    sa.UniqueConstraint('uuid')
    )
    ### end Alembic commands ###
Run Code Online (Sandbox Code Playgroud)

感谢Michael的所有帮助!

  • 我发现了它:在我的其他项目中,我在文件(__init__.py)中导入了“Base”和模型,并从这个“__init__.py”文件中导入了“env.py”中的“Base”。 (3认同)
  • 好吧,它也对我有用。但在其他项目中,我从来不需要将模型导入到“env.py”,只需“Base.metadata”本身就可以了。我检查了这些其他项目,但我找不到任何关于它们为什么有效的线索,而我当前的项目却不能!我已经完成了相同的配置,并且在我的实际项目中,自动生成仅在我导入模型本身时才起作用! (2认同)

小智 12

一切都变得更加简单,从开始阅读文档开始,我就解决了自动生成迁移的问题。不要忘记 在 env.py 文件中将target_metadataNone 更改为 。Base.metadata

target_metadata = Base.metadata
Run Code Online (Sandbox Code Playgroud)

以及导入您想要在__init__.py模块中跟踪的所有模型,其中包含从基本模型继承的所有数据库模型。然后你只需要在你的 env.py 中导入这些 Base

from app.database.models import Base
Run Code Online (Sandbox Code Playgroud)

就是这样!

  • 这个答案有效,特别是从模型文件导入“Base”的原因是因为每个模型都继承自“Base”。当您从“models”文件导入“Base”时,它会继承所有模型,因为导入会自动评估每个新模型的类定义,并且“Base”将每个模型添加到自身,然后在“target_metadata”中使用。如果您不从“models”导入,则“Base”永远没有机会与应用程序中的每个真实“模型”关联。 (3认同)

moo*_*834 7

详细分享一下(不过其他人已经口头回答了),不需要在里面一一导入模型的方式env.py

models/
    __init__.py
    base.py
    yourmodel1.py
    yourmodel2.py
alembic/
    versions/
    env.py
Run Code Online (Sandbox Code Playgroud)

__init.py__

from models.base import Base
from models.yourmodel2 import yourmodel2
from models.yourmodel1 import yourmodel2
Run Code Online (Sandbox Code Playgroud)

base.py

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
Run Code Online (Sandbox Code Playgroud)

yourmodel1.py

from models.base import Base

class Yourmodel1(Base):
    # define columns here
Run Code Online (Sandbox Code Playgroud)

对其他模型文件执行相同操作

添加env.py以下内容:

from models import Base
target_metadata = Base.metadata
Run Code Online (Sandbox Code Playgroud)

然后就可以运行自动升级了^_^


小智 6

我遇到了同样的问题,我通过从文件(目录中的注释文件)导入类来解决它,如下所示:

from db.db_setup import Base
from db.models.user import User
from db.models.course import Course
Run Code Online (Sandbox Code Playgroud)

然后删除所有表和自动生成的文件,然后alembic revision --autogenerate再次运行。


kun*_*phu 5

我认为这里值得指出的是,我在当前版本(0.8.4)中也遇到了同样的问题,但是设置元数据的方法似乎变得更加明确:除了导入模型之外,还需要设置target_metadata(其中存在于env.py但默认为None)。

文件表明,进口的东西,他们所谓的Base,但目前还不清楚究竟是; 导入我的模型继承的 DeclarativeBase 实例对我没有任何作用(与 OP 相同的结果)。

但是,代码中的实际注释建议target_metadata使用实际模型 ( ModelNameHere.metadata) 进行设置,这对我有用(使用一个模型的元数据导致所有模型都被检测到)。

  • 您不仅需要导入 DeclarativeBase,还需要导入从它继承的每个模型。 (3认同)