我想在create table之后运行一些自定义DDL语句:
update_function = DDL("""
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'pgplsql';
""")
update_trigger = DDL("""
CREATE TRIGGER update %(table)s_timestamp BEFORE UPDATE
ON %(table)s FOR EACH ROW EXECUTE PROCEDURE update_timestamp();
""")
我已经像这样附上了他们:
event.listen(Session.__table__, 'after_create', update_function)
event.listen(Session.__table__, 'after_create', update_trigger)
当我create_all
时,我得到了我期望的SQL:
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'pgplsql';
CREATE TRIGGER update session_timestamp BEFORE UPDATE
ON session FOR EACH ROW EXECUTE PROCEDURE update_timestamp();
但是当我使用Alembic升级时,语句不会出现:
-- Running upgrade c0d470e5c81 -> 6692fad7378
CREATE TABLE session (
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT 'CURRENT_TIMESTAMP',
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT 'CURRENT_TIMESTAMP',
id VARCHAR(32) NOT NULL,
owner_id INTEGER,
database_id VARCHAR(32),
content TEXT,
PRIMARY KEY (id),
FOREIGN KEY(database_id) REFERENCES database (id),
FOREIGN KEY(owner_id) REFERENCES users (id)
);
INSERT INTO alembic_version (version_num) VALUES ('6692fad7378');
有没有办法让alembic触发'after_create'事件?
答案 0 :(得分:9)
发出表级别before_create / after_create事件(不是元数据级别的事件)。您需要确保env.py脚本中发生的任何事情最终都涉及正在设置的事件监听器。
你在这里的代码看起来有点怀疑:
event.listen(Session.__table__, 'after_create', update_function)
event.listen(Session.__table__, 'after_create', update_trigger)
Session.__table__
这里只是一个Table
实例,这可能不是你在alembic脚本中看到的。 alembic create_table
命令在本地创建Table
并在其上运行创建,因此您需要全局监听所有Table对象:
from sqlalchemy import Table
event.listen(Table, 'after_create', update_function)
event.listen(Table, 'after_create', update_trigger)
如果这些事件仅针对这一个特定的表,那么你就不会使用任何事件,只需将这些触发器的DDL()直接放在迁移脚本中,就在它调用{{1 }}
答案 1 :(得分:4)
扩展@zzzeek的答案,这个助手适合我:
from sqlalchemy import Table
from sqlalchemy.event import listen
from functools import partial
def on_table_create(class_, ddl):
def listener(tablename, ddl, table, bind, **kw):
if table.name == tablename:
ddl(table, bind, **kw)
listen(Table,
'after_create',
partial(listener, class_.__table__.name, ddl))
然后你做:
on_table_create(Session, update_function)
on_table_create(Session, update_trigger)
答案 2 :(得分:0)
这个解决方案对我帮助很大:https://gist.github.com/jasco/5f742709088f80f07eb2e0d6a141d3f2
因此,如果您有一个带有侦听器的 DDL,请将其放入一个变量中:
create_table_ddl = DDL("...").execute_if(dialect='postgresql')
drop_table_ddl = DDL("...").execute_if(dialect='postgresql')
event.listen(Model.__table__, 'after_create', create_table_ddl)
event.listen(Model.__table__, 'before_drop', drop_table_ddl)
在迁移中手动执行此操作:
def upgrade():
create_table_ddl(target=None, bind=op.get_bind())
def upgrade():
drop_table_ddl(target=None, bind=op.get_bind())
Alembic 不会调用您的桌面事件