有没有一种很好的方法可以在SQLAlchemy中禁用DML?

时间:2017-03-16 16:36:43

标签: python sqlalchemy

我想在我的脚本中添加--dry-run选项,以防止它向数据库发出任何更新。我想要记录一些东西(例如它会运行的语句)。

在SQLAlchemy中有没有很好的方法来实现它?例如。在Session对象中切换/ monkey-patch是否有充分记录的内容?

1 个答案:

答案 0 :(得分:1)

这是一个简单的示例脚本joins the session to an existing transactional connection,如果给出正确的开关,则回滚。

import argparse
from contextlib import contextmanager
from sqlalchemy import create_engine, table, column
from sqlalchemy.orm import sessionmaker
import logging

_Session = sessionmaker()
logging.basicConfig()


@contextmanager
def _destructive_run(engine):
    session = _Session(bind=engine)
    try:
        yield session

    finally:
        session.close()


@contextmanager
def _dry_run(engine):
    logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
    conn = engine.connect()
    trans = conn.begin()
    session = _Session(bind=conn)
    try:
        yield session

    finally:
        session.close()
        trans.rollback()
        conn.close()

_args = argparse.ArgumentParser("Super Dry Runner")
_args.add_argument("--dry-run", dest='context', action='store_const',
                   const=_dry_run, default=_destructive_run)
_args.add_argument("engine", metavar="DB_URL", type=create_engine)
_args.add_argument("values", metavar="VALUE", nargs="+",
                   type=lambda v: { "value": v })


def main(*, engine, context, values):
    with context(engine) as session:
        table1 = table("table1", column("value"))
        session.execute(table1.insert().values(values))
        session.commit()

if __name__ == '__main__':
    main(**vars(_args.parse_args()))

示例运行:

 % sqlite3 test.db "create table table1 (value text);"
 % python dry.py sqlite:///test.db test1 test2 test3            
 % sqlite3 test.db "select * from table1;"            
test1
test2
test3
 % python dry.py --dry-run sqlite:///test.db test4 test5 test6
INFO:sqlalchemy.engine.base.Engine:SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
INFO:sqlalchemy.engine.base.Engine:()
INFO:sqlalchemy.engine.base.Engine:SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
INFO:sqlalchemy.engine.base.Engine:()
INFO:sqlalchemy.engine.base.Engine:BEGIN (implicit)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO table1 (value) VALUES (?), (?), (?)
INFO:sqlalchemy.engine.base.Engine:('test4', 'test5', 'test6')
INFO:sqlalchemy.engine.base.Engine:ROLLBACK
 % sqlite3 test.db "select * from table1;"                    
test1
test2
test3