使用声明基类派生对象创建alembic表
我有一个 Alchemy ORM 对象:
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class MyORM(Base):
id = Column(Integer, primary_key=True)
name = Column(String(128), unique=True, nullable=False)
当我使用 alembic 来创建表的时候,我是这样做的:
def upgrade():
op.create_table(
'myorm',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('name', sa.String(128), nullable=False),
)
问题:有没有办法用 MyORM 类来创建这个表?类似这样:
def upgrade():
op.create_table(
'myorm',
sa.BaseObject(MyORM)
)
1 个回答
10
这正是Alembic迁移想要避免的情况。如果你把迁移和你模型的当前状态绑在一起,那就不会有一个稳定的升级路径。
你可以在迁移中使用声明式方法来创建表和迁移数据,但不能用来修改表结构。你需要把定义重新创建,与应用程序的定义分开。这在你想进行数据迁移时会很有用,特别是当你对ORM查询更熟悉,而不是核心查询时。
下面是一个示例迁移,它使用声明式方法创建了Foo和Bar模型,并建立了多对多的关系,同时创建了表并插入了一些数据。
"""declarative
Revision ID: 169ad57156f0
Revises: 29b4c2bfce6d
Create Date: 2014-06-25 09:00:06.784170
"""
revision = '169ad57156f0'
down_revision = '29b4c2bfce6d'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
Session = sessionmaker()
Base = declarative_base()
class Foo(Base):
__tablename__ = 'foo'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, nullable=False, unique=True)
class Bar(Base):
__tablename__ = 'bar'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, nullable=False, unique=True)
foos = relationship(Foo, lambda: foo_bar, backref='bars')
foo_bar = sa.Table(
'foo_bar', Base.metadata,
sa.Column('foo_id', sa.Integer, sa.ForeignKey('foo.id'), primary_key=True),
sa.Column('bar_id', sa.Integer, sa.ForeignKey('bar.id'), primary_key=True)
)
def upgrade():
bind = op.get_bind()
Base.metadata.create_all(bind=bind)
session = Session(bind=bind)
session._model_changes = False # if you are using Flask-SQLAlchemy, this works around a bug
f1 = Foo(name='f1')
f2 = Foo(name='f2')
b1 = Bar(name='b1')
b2 = Bar(name='b2')
f1.bars = [b1, b2]
b2.foos.append(f2)
session.add_all([f1, f2, b1, b2])
session.commit()
def downgrade():
bind = op.get_bind()
# in this case all we need to do is drop the tables
# Base.metadata.drop_all(bind=bind)
# but we could also delete data
session = Session(bind=bind)
session._model_changes = False # if you are using Flask-SQLAlchemy, this works around a bug
b1 = session.query(Bar).filter_by(name='b1').one()
session.delete(b1)
session.commit()