2013-05-18 3 views
7

Ich habe ein paar von benutzerdefinierten DDL-Anweisungen, die ich nach Tabelle erstellen ausgeführt werden soll:Wie bekomme ich Alambic, um benutzerdefinierte DDL auf after_create zu emittieren?

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(); 
""") 

Und ich habe sie so angebracht:

event.listen(Session.__table__, 'after_create', update_function) 
event.listen(Session.__table__, 'after_create', update_trigger) 

Als ich create_all tun, ich holen Sie sich die SQL ich erwarte:

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(); 

Aber wenn ich Alembic Upgrade verwenden, sollten Sie die Anweisungen nicht erscheinen:

-- 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'); 

Gibt es eine Möglichkeit, Alembic dazu zu bringen, die 'after_create'-Ereignisse auszulösen?

Antwort

8

Die Ereignisse der Tabelle level before_create/after_create werden ausgegeben (nur nicht die der Metadatenebene). Sie müssen sicherstellen, dass alles, was in Ihrem env.py-Skript passiert, letztlich die Ereignis-Listener berücksichtigt, die eingerichtet werden.

Der Code, den Sie hier haben sieht ein wenig suspekt: ​​

event.listen(Session.__table__, 'after_create', update_function) 
event.listen(Session.__table__, 'after_create', update_trigger) 

Session.__table__ hier würde nur eine einzige Table Instanz sein und das ist wahrscheinlich nicht das, was Sie im alembic Skript sehen würde. Der alembic create_table Befehl erstellt eine Table lokal und läuft nur auf es schaffen, so müssten Sie hören auf alle Tabelle global Objekte:

from sqlalchemy import Table 
event.listen(Table, 'after_create', update_function) 
event.listen(Table, 'after_create', update_trigger) 

, wenn diese Ereignisse allerdings nur für diese eine bestimmte Tabelle sind, können Sie dann Wenn Sie keine Ereignisse verwenden würden, würden Sie DDL() für diese Trigger direkt in Ihr Migrationsskript schreiben, gleich nachdem, wo es create_table() aufruft.

+0

Danke für die Erklärung. –

4

Erweiterung auf @ zzzeek Antwort, diese Helfer funktioniert für mich:

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)) 

Dann würden Sie tun:

on_table_create(Session, update_function) 
on_table_create(Session, update_trigger)