为什么Flask Migrate要我执行两步迁移?

为什么Flask Migrate要我执行两步迁移?,flask,alembic,flask-migrate,Flask,Alembic,Flask Migrate,我正在与Flask、SQLAlchemy、Alembic及其Flask包装(Flask SQLAlchemy和Flask Migrate)合作一个项目。我有四次迁移: 1c5f54d4aa34 -> 4250dfa822a4 (head), Feed: Countries 312c1d408043 -> 1c5f54d4aa34, Feed: Continents 41984a51dbb2 -> 312c1d408043, Basic Structure <base>

我正在与Flask、SQLAlchemy、Alembic及其Flask包装(Flask SQLAlchemy和Flask Migrate)合作一个项目。我有四次迁移:

1c5f54d4aa34 -> 4250dfa822a4 (head), Feed: Countries
312c1d408043 -> 1c5f54d4aa34, Feed: Continents
41984a51dbb2 -> 312c1d408043, Basic Structure
<base> -> 41984a51dbb2, Init Alembic
如果我要求Flask Migrate运行除最后一个迁移之外的所有迁移,那么它可以工作。如果在此之后再次运行upgrade命令,则该命令有效–即,它完全升级我的数据库,而无需对代码进行任何更改:

vagrant@precise32:/vagrant$ python manage.py db upgrade 312c1d408043
INFO  [alembic.migration] Context impl PostgresqlImpl.
INFO  [alembic.migration] Will assume transactional DDL.
INFO  [alembic.migration] Running upgrade  -> 41984a51dbb2, Init Alembic
INFO  [alembic.migration] Running upgrade 41984a51dbb2 -> 312c1d408043, Basic Structure

vagrant@precise32:/vagrant$ python manage.py db upgrade
INFO  [alembic.migration] Context impl PostgresqlImpl.
INFO  [alembic.migration] Will assume transactional DDL.
INFO  [alembic.migration] Running upgrade 312c1d408043 -> 1c5f54d4aa34, Feed: Continents
INFO  [alembic.migration] Running upgrade 1c5f54d4aa34 -> 4250dfa822a4, Feed: Countries
TL;DR

上一次迁移(提要:Countries)在上一次迁移(提要:大陆)提供的表上运行查询。如果我有大陆表创建和饲料,脚本应该工作。但事实并非如此。 为什么我必须停止迁移过程,然后在另一个命令中重新启动它?我真的不明白。是Alembic在一系列迁移之后执行的命令吗?有什么想法吗

以防万一

我的模型定义如下:

类别国家/地区(数据库型号):
__tablename_uuu=‘国家’
id=db.Column(db.Integer,主键=True)
alpha2=db.Column(db.String(2),index=True,unique=True)
title=db.Column(db.String(140))
Continental_id=db.Column(db.Integer,db.ForeignKey('Continental.id'))
大陆=数据库关系(“大陆”,backref='countries')
定义报告(自我):
返回“”。格式(self.id,self.title)
类别(数据库模型):
__tablename_uuu='大陆'
id=db.Column(db.Integer,主键=True)
alpha2=db.Column(db.String(2),index=True,unique=True)
title=db.Column(db.String(140))
定义报告(自我):
返回“”。格式(self.id,self.title)
非常感谢,

更新1:最近两次迁移的升级方法

正如@Miguel在评论中所问的,以下是最近两次迁移的升级方法:

1c5f54d4aa34 -> 4250dfa822a4 (head), Feed: Countries
312c1d408043 -> 1c5f54d4aa34, Feed: Continents
41984a51dbb2 -> 312c1d408043, Basic Structure
<base> -> 41984a51dbb2, Init Alembic
饲料:大陆

def升级():
csv_path=app.config['BASEDIR'].child('migrations','csv','en')
csv_file=csv_path.child('columents.csv')
使用打开(csv_文件)作为文件_处理程序:
csv=列表(读卡器(文件处理程序))
csv.pop(0)
数据=[{'alpha2':c[0]。小写(),'title':c[1]}用于csv中的c]
op.bulk\U插入(大陆、表格、数据)
提要:国家(取决于上次移民时的提要表)

def升级():
#加载国家iso3166.csv并构建字典
csv_path=app.config['BASEDIR'].child('migrations','csv','en')
csv_file=csv_path.child('iso3166.csv'))
国家=dict()
使用打开(csv_文件)作为文件_处理程序:
csv=列表(读卡器(文件处理程序))
对于csv中的c:
国家[c[0]]=c[1]
#从country_continent.csv加载国家/地区/大陆
csv\u file=csv\u path.child('country\u contraction.csv')
使用打开(csv_文件)作为文件_处理程序:
csv=列表(读卡器(文件处理程序))
country_Continental=[{'country':c[0],'Continental':c[1]}表示csv中的c]
#环路
数据=列表()
对于国家/地区/大陆的项目:
#获取大陆id
大陆猜=项目['Continental']。下()
Continental=Continental.query.filter_by(alpha2=Continental_guess).first()
#包括国家
如果大陆不是无:
country\u name=countries.get(项['country'],False)
如果国家/地区名称:
data.append({'alpha2':项['country'].lower(),
“标题”:国家名称,
'大陆_id':大陆.id})
我使用的CSV基本上遵循以下模式:

大陆公司

iso3166.csv

_国家/地区/大陆.csv_

...
US,NA
UY,SA
UZ,AS
...
因此,提要:大陆为大陆表提供提要,提要:国家为国家表提供提要。但它必须查询大陆表,以便在国家和大陆之间建立适当的联系

更新2:Reddit的一些人已经提供了解释和解决方法

我问,然后说:

我以前也遇到过这种情况,问题是迁移不会 单独执行,但改为alembic批处理全部(或全部 然后执行SQL。这意味着 当最后一次迁移尝试运行时,表没有运行 实际上还存在,所以不能进行查询。做

from alembic import op

def upgrade():
    #migration stuff
    op.execute('COMMIT')
    #run queries
这并不是最优雅的解决方案(对于Postgres来说,这是最优雅的解决方案) 命令可能与其他dbs不同),但它对我有效。也, 这实际上不是一个问题,而是一个问题 有了alembic,如果你想在谷歌上搜索更多信息,请搜索 阿勒姆比奇。Flask Migrate只是一个围绕alembic的包装器,可以工作 轻松地使用Flask脚本


正如reddit上的@TheMath魔术师所指出的,默认情况下,Alembic在一个事务中运行所有迁移,因此根据数据库引擎和迁移脚本中的操作,依赖于先前迁移中添加的内容的某些操作可能会失败

我自己也没有尝试过,但是Alembic0.6.5引入了一个
transaction\u per\u migration
选项,可以解决这个问题。这是
configure()
调用
env.py
的一个选项。如果在Flask Migration创建默认配置文件时使用这些文件,则在
migrations/env.py
中可以解决此问题:

def run_migrations_online():
    """Run migrations in 'online' mode.

    # ...
    context.configure(
                connection=connection,
                target_metadata=target_metadata,
                transaction_per_migration=True        # <-- add this
                )
    # ...
def run_migrations_online():
“”“在“联机”模式下运行迁移。
# ...
context.configure(
连接=连接,
target\u metadata=target\u metadata,

transaction_per_migration=True#你能添加上两次迁移的
upgrade()
方法吗?@Miguel,谢谢,刚刚编辑了帖子并添加了方法。顺便说一句,我已经对你说了“谢谢”,但也许你还没有看到它-所以,再分享一次哈哈…
from alembic import op

def upgrade():
    #migration stuff
    op.execute('COMMIT')
    #run queries
def run_migrations_online():
    """Run migrations in 'online' mode.

    # ...
    context.configure(
                connection=connection,
                target_metadata=target_metadata,
                transaction_per_migration=True        # <-- add this
                )
    # ...