15

我正在使用 Alembic 来处理 Flask 的迁移。alembic revision --autogenerate理论上,应该根据我的数据库中的更改自动生成迁移。但是,Alembic 只是使用上述命令生成空白迁移。

有一个与这个问题非常相似的问题,问题是没有导入正确的模型。但是,我已经从我的 Flask 应用程序中导入了模型,如下所示env.py

...
# import settings from Flask
alembic_config = config.get_section(config.config_ini_section)
from start import app
from models import User, Item, Recipient # models are imported here from models.py
alembic_config['sqlalchemy.url'] = app.config['SQLALCHEMY_DATABASE_URI']

engine = engine_from_config(
            alembic_config, # config.get_section(config.config_ini_section)
            prefix='sqlalchemy.',
            poolclass=pool.NullPool)
...

以及导入的数据库元数据env.py('start' 是我的 Flask 应用程序主文件的名称):

...
from start import db
target_metadata = db.metadata
...

然后运行alembic revision --autogenerate -m "initial_rev"会生成一个空迁移,尽管我的 Flask 应用程序会有所不同:

"""initial_rev

Revision ID: 45296fd29540
Revises: None
Create Date: 2013-06-19 17:32:38.392268

"""

# revision identifiers, used by Alembic.
revision = '45296fd29540'
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 ###

编辑

这是一个要点,它显示了我的应用程序的文件结构,以及一些附加代码。似乎问题是 Alembic 不喜欢在database.py没有先在__init__.py. 但是,当使用蓝图时这是不可能的(因为周期性导入),在这个 SO 答案中解释:https ://stackoverflow.com/a/9695045/353878 。

那么问题来了,在同时使用 Flask 蓝图的情况下如何使用 Alembic?

编辑#2

我什至尝试打印db.metadata.sorted_tables,以确保正确导入数据库元数据。果然,整个数据库模式通过管道传输到终端。那么为什么 Alembic 会生成空白的升级/降级功能呢?

编辑#3

我已经得出结论,这个问题与 和 的差异有关db.init_app(app)db = SQLAlchemy(app)但我不太确定是什么导致了这个问题。为了测试这个理论,我替换from database import db为. 可能是个坏主意,但我想看看出于调试目的会发生什么。env.pydb = SQLAlchemy(app)

Alembic 自动生成并填充了 upgrade() 和 downgrade() 方法——除了它们被颠倒了!upgrade()删除了我的所有三个表,同时downgrade()使用所有正确的列和元数据创建它们。我不知道为什么会这样,但我希望它对试图解决这个问题的人有所帮助。

4

1 回答 1

28

这是我如何将 Alembic 与 Flask 和蓝图一起使用。

https://github.com/davidism/basic_flask

我使用应用程序工厂模式并db.init_app在其中调用。在db = SQLAlchemy()我导入所有将子类化的模型之后,db.Model以便db.metadata了解它们;请注意,这不是在create_app工厂完成的,而只是在模块初始化期间内联。

运行alembic时,项目文件夹不包含在其中,sys.path因此我进行了设置。然后我从工厂创建一个应用程序并sqlalchemy.url从其配置中进行设置。另外,我导入db并设置target_metadata = db.metadata.

无论项目结构如何,此设置始终对我有用。我在带有蓝图的子包中包含了一组非常基本的用户模型和一个非常愚蠢的视图。只需确保在 中加载相关模型load_models,在定义蓝图后导入视图,然后在init_views.

于 2013-06-25T16:30:14.517 回答