【问题标题】:Alembic/Flask-Migrate not detecting after_create eventsAlembic/Flask-Migrate 未检测到 after_create 事件
【发布时间】:2016-07-27 02:52:43
【问题描述】:

我有一个简单的 Flask-SQLAlchemy 模型(带有事件监听器来创建触发器):

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Confirm(db.Model):
  created = db.Column(db.DateTime, default=db.func.current_timestamp(), nullable=False)
  modified = db.Column(db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp(), nullable=False)
  id = db.Column(db.String(36), primary_key=True) 

class ConfirmOld(db.Model):
  orig_created = db.Column(db.DateTime)
  orig_modified = db.Column(db.DateTime)
  orig_id = db.Column(db.String(36))

confirm_delete = DDL('''\
CREATE TRIGGER confirm_delete 
BEFORE DELETE
  ON confirm FOR EACH ROW
  BEGIN
    INSERT INTO confirm_old ( orig_created, orig_modified, orig_id )
    VALUES ( OLD.created, OLD.modified, OLD.id );
  END;
''')

event.listen(Confirm.__table__, 'after_create', confirm_delete)

当我运行 Alembic 迁移和升级时,不会创建 TRIGGER(在 MySQL 中)。但是,当我使用 db.create_all() 时,它是创建并正常工作的。

是否可以让 Alembic / Flask-Migrate 创建和管理我的触发器(即在 after_create 事件上运行的自定义 DDL)?

【问题讨论】:

  • 不确定为什么当您通过 Alembic 时触发器没有触发,但我可以告诉您,如果您正在使用迁移,最好将触发器创建包含在迁移脚本中,而不是在 SQLAlchemy 事件中。
  • 听起来不错 - 有没有办法跟踪活动 DDL 的当前状态?我的意思是跟踪迁移历史中的每个步骤(这是您建议的)以及触发器的当前活动状态(或任何 DDL)?
  • 不确定我是否理解这个问题。事实上,有了迁移脚本,您就有了非常明确的模式历史记录。回想一下,迁移脚本具有升级和降级功能,这允许您跳转到数据库架构历史中的任何点。
  • Alembic 不会自动检测自定义 DDL。您应该查看文档的 Replaceable Objects 部分,该部分概述了如何更轻松地管理触发器、函数和视图。
  • @univerio,该链接现已失效,但此链接(当前)有效:Replacable Objects

标签: flask sqlalchemy flask-sqlalchemy alembic flask-migrate


【解决方案1】:

我遇到了同样的问题,尝试了一个可替换对象的解决方案,但没有奏效:

我设法通过编辑迁移脚本并执行触发器创建查询使其工作。

步骤如下:

  • 运行flask db migrate -m 'adding custom trigger on table x,它将在迁移文件夹的版本子文件夹下为您生成一个迁移脚本。

  • 检查在版本下创建的文件夹并像这样编辑它:

像这样创建您的触发器查询:

在文件中:

trigger = '''
CREATE TRIGGER confirm_delete
BEFORE DELETE
ON confirm FOR EACH ROW
BEGIN
INSERT INTO confirm_old ( orig_created, orig_modified, orig_id )
VALUES ( OLD.created, OLD.modified, OLD.id );
END;
'''

在升级方法中:

添加这一行:

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###

    # ### end Alembic commands ###

    ### add your queries here execute
    op.execute(trigger)

如果你运行flask db upgrade,它将执行查询并更新数据库

要降级数据库,请在降级方法中添加:

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    # ### end Alembic commands ###
    op.execute('drop trigger if exists confirm_delete on confirm cascade;')

如果您检查您的数据库更改将被应用。

PS:更优雅的解决方案应该是建议here

使用可替换对象,尝试过但它不起作用可能是我的 alembic 没有更新。

解决方案如下所示:

创建一个 ReplaceableObjects 类:

class ReplaceableObject(object):
    def __init__(self, name, sqltext):
        self.name = name
        self.sqltext = sqltext

用您的查询语句实例化它。

delete_trigger = ReplaceableObject('delete_trigger', trigger)

像这样更新你的升级和降级功能:

def upgrade():
    op.create_sp(delete_trigger)


def downgrade():
    op.drop_sp(delete_trigger)

希望它能帮助其他人......

【讨论】:

    猜你喜欢
    • 2018-12-11
    • 2023-02-02
    • 2020-09-26
    • 2019-07-13
    • 2015-07-15
    • 2021-11-08
    • 2014-12-21
    • 2019-01-17
    • 2015-07-20
    相关资源
    最近更新 更多