python - 在 Alembic 迁移中使用 SQLAlchemy ORM : how do I?

标签 python sqlalchemy alembic

我目前有一个包含 HTML 标记的列。在该标记内,有一个我想存储在新列中的时间戳(因此我可以查询它)。我的想法是在一次迁移中执行以下操作:

  1. 为数据创建一个新的可为空的列
  2. 使用 ORM 拉回我需要解析的 HTML
  3. 对于每一行
    1. 解析 HTML 以提取时间戳
    2. 更新ORM对象

但是当我尝试运行迁移时,它似乎陷入了无限循环。到目前为止,这是我得到的:

def _extract_publication_date(html):
    root = html5lib.parse(html, treebuilder='lxml', namespaceHTMLElements=False)
    publication_date_string = root.xpath("//a/@data-datetime")[0]
    return parse_date(publication_date)


def _update_tip(tip):
    tip.publication_date = _extract_publication_date(tip.rendered_html)
    tip.save()


def upgrade():
    op.add_column('tip', sa.Column('publication_date', sa.DateTime(timezone=True)))
    tips = Tip.query.all()
    map(tips, _update_tip)


def downgrade():
    op.drop_column('tip', 'publication_date')

最佳答案

在使用@velochy 的回答进行了一些实验之后,我确定了类似以下在 Alembic 中使用 SqlAlchemy 的模式。这对我很有用,可以作为 OP 问题的通用解决方案:

from sqlalchemy.orm.session import Session
from alembic import op

# Copy the model definitions into the migration script if
# you want the migration script to be robust against later
# changes to the models. Also, if your migration includes
# deleting an existing column that you want to access as 
# part of the migration, then you'll want to leave that 
# column defined in the model copies here.
class Model1(Base): ...
class Model2(Base): ...

def upgrade():
    # Attach a sqlalchemy Session to the env connection
    session = Session(bind=op.get_bind())

    # Perform arbitrarily-complex ORM logic
    instance1 = Model1(foo='bar')
    instance2 = Model2(monkey='banana')

    # Add models to Session so they're tracked
    session.add(instance1)
    session.add(instance2)

    # Apply a transform to existing data
    m1s = session.query(Model1).all()
    for m1 in m1s:
        m1.foo = transform(m1.foo)
    session.commit()

def downgrade():
    # Attach a sqlalchemy Session to the env connection
    session = Session(bind=op.get_bind())

    # Perform ORM logic in downgrade (e.g. clear tables)
    session.query(Model2).delete()
    session.query(Model1).delete()

    # Revert transform of existing data
    m1s = session.query(Model1).all()
    for m1 in m1s:
        m1.foo = un_transform(m1.foo)
    session.commit()

这种方法似乎可以正确处理事务。在处理此问题时,我经常会生成数据库异常,它们会按预期回滚。

关于python - 在 Alembic 迁移中使用 SQLAlchemy ORM : how do I?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13676744/

相关文章:

python - 如何使 df.to_sql() 创建 varchar2 对象

python - 在 Flask-SQLAlchemy session 之外保存到数据库

python - 如何使用 alembic 将 MySQL 表转换为 utf8 字符集?

python - 多页 Dash 应用程序

java - 如何运行 Python 解释器并使用 Java 获取其输出?

python - 运行并发请求时获取 "Invalid cursor state (0)"(SQLAlchemy & wsgi/python)

python - Alembic 是否可以应用于现有数据库,并在检测到表/列已存在时跳过创建/更改表/列?

python - Alembic --autogenerate 产生空迁移

python - 无法使用 pip 下载 pyxplorer 包?

python - ROBOT 框架在内置库关键字 'run_keyword_and_continue_on_failure' 中使用 selenium2library 关键字时出现问题