SQLAlchemy从create()打印原始SQL

67

我正在尝试使用SQLAlchemy来编写Pylons应用程序,我很喜欢它,只有一件事情让我困惑,那就是在执行Table().create()之前,是否有可能打印出所生成的原始SQL CREATE TABLE数据?

6个回答

126
from sqlalchemy.schema import CreateTable

print(CreateTable(table))
如果您正在使用声明性语法:
print(CreateTable(Model.__table__))

更新:

由于我已经有了被接受的答案,并且klenwell的回答中有重要信息,所以我也会在这里添加它。

通过编译您的引擎,您可以获取特定数据库(MySQL、Postgresql等)的SQL语句。

print(CreateTable(Model.__table__).compile(engine))

更新2:

@jackotonye在评论中添加了一种不需要引擎的方法。

print(CreateTable(Model.__table__).compile(dialect=postgresql.dialect()))

这对于模型来说是有效的,但是在多对多关系中,我该如何打印出关联表呢?因为整个系统需要它们才能正常工作。 - tchen
1
太好了,这对我有用!但是,我仍然无法看到在声明语法__table_args__成员定义的索引。有任何想法吗? - Pehat
5
这也可以在没有引擎的情况下完成。print(CreateTable(Model.__table__).compile(dialect=postgresql.dialect())) - jackotonye
1
使用mysqlconnector的示例:from sqlalchemy.dialects.mysql import mysqlconnector print(CreateTable(AttribResults.__table__).compile(dialect=mysqlconnector.dialect())) - glefait
1
@Guus,这是你编写的继承自declarative_base的类之一。例如:class User(Base):(在该示例中,UserModel)。 - Antoine Leclair
显示剩余2条评论

20

您可以设置引擎以转储元数据创建序列,使用以下内容:

def metadata_dump(sql, *multiparams, **params):
    # print or write to log or file etc
    print(sql.compile(dialect=engine.dialect))

engine = create_engine(myDatabaseURL, strategy='mock', executor=metadata_dump)
metadata.create_all(engine)

这种方法的一个优点是枚举和索引包含在打印输出中。使用CreateTable则会排除它们。

另一个优点是模式定义的顺序是正确的,(几乎)可以用作脚本。


2
如果您使用需要分号的关系型数据库管理系统,请将函数体替换为 print(str(sql.compile(dialect=engine.dialect)) + ";"),以获取输出中的分号。 - Tim Coker
在新版本(1.4)中,它看起来有点不同: engine = create_mock_engine("postgresql://", metadata_dump)metadata.create_all(engine, checkfirst=False) - Alexander
有趣的方法。所以你是从引擎对象中提取查询。 - justdan23

15

我需要获取原始表格的SQL以便为一些现有模型设置测试。这是我基于Antoine的答案创建的适用于SQLAlchemy 0.7.4的成功单元测试,作为概念验证:

from sqlalchemy import create_engine
from sqlalchemy.schema import CreateTable
from model import Foo

sql_url = "sqlite:///:memory:"    
db_engine = create_engine(sql_url)

table_sql = CreateTable(Foo.table).compile(db_engine)
self.assertTrue("CREATE TABLE foos" in str(table_sql))

8

虽然这个链接可能回答了问题,但最好在这里包含答案的关键部分,并提供链接作为参考。仅有链接的答案如果链接页面发生变化,就可能失效。- 来自评论 - EsmaeelE

7
原来这很简单:
from sqlalchemy.dialects import postgresql
from sqlalchemy.schema import CreateTable
from sqlalchemy import Table, Column, String, MetaData

metadata = MetaData()

users = Table('users', metadata,
              Column('username', String)
)

statement = CreateTable(users)

print(statement.compile(dialect=postgresql.dialect()))

输出结果如下:
CREATE TABLE users (
    username VARCHAR
)

进一步来说,它甚至可以支持准备好的语句中的绑定参数。

参考资料

How do I render SQL expressions as strings, possibly with bound parameters inlined?

...

or without an Engine:

from sqlalchemy.dialects import postgresql
print(statement.compile(dialect=postgresql.dialect()))

示例:使用SQLAlchemy生成用户重命名脚本

来源:http://docs.sqlalchemy.org/en/latest/faq/sqlexpressions.html#faq-sql-expression-string

#!/usr/bin/env python
import csv
from sqlalchemy.dialects import postgresql
from sqlalchemy import bindparam, Table, Column, String, MetaData

metadata = MetaData()

users = Table('users', metadata,
              Column('username', String)
)

renames = []

with open('users.csv') as csvfile:
    for row in csv.DictReader(csvfile):
        renames.append({
            'from': row['sAMAccountName'],
            'to': row['mail']
        })

for rename in renames:
    stmt = (users.update()
            .where(users.c.username == rename['from'])
            .values(username=rename['to']))
    print(str(stmt.compile(dialect=postgresql.dialect(),
                           compile_kwargs={"literal_binds": True})) + ';')

处理这个 users.csv 文件时:

sAMAccountName,mail
bmcboatface,boaty.mcboatface@example.com
ndhyani,naina.dhyani@contoso.com

输出如下所示:
UPDATE users SET username='boaty.mcboatface@example.com' WHERE users.username = 'bmcboatface';
UPDATE users SET username='naina.dhyani@contoso.com' WHERE users.username = 'ndhyani';users.username = 'ndhyani';

为什么一艘研究船有一个电子邮件地址尚未确定。我已经联系了Example公司的IT团队,但没有得到回复。


1
最佳答案,组织良好且可运行。谢谢! - Devy
非常乐意,@Devy。感谢您独立确认它可以正常工作 :) - Alain O'Dea

4

也许你指的是sqlalchemy.create_engine()函数中的echo参数?

/tmp$ cat test_s.py

import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Department(Base):
    __tablename__ = "departments"

    department_id = sa.Column(sa.types.Integer, primary_key=True)
    name = sa.Column(sa.types.Unicode(100), unique=True)
    chief_id = sa.Column(sa.types.Integer)
    parent_department_id = sa.Column(sa.types.Integer,
                                     sa.ForeignKey("departments.department_id"))

    parent_department = sa.orm.relation("Department")


engine = sa.create_engine("sqlite:///:memory:", echo=True)
Base.metadata.create_all(bind=engine)

/tmp$ python test_s.py

2011-03-24 15:09:58,311 INFO sqlalchemy.engine.base.Engine.0x...42cc PRAGMA table_info("departments")
2011-03-24 15:09:58,312 INFO sqlalchemy.engine.base.Engine.0x...42cc ()
2011-03-24 15:09:58,312 INFO sqlalchemy.engine.base.Engine.0x...42cc 
CREATE TABLE departments (
    department_id INTEGER NOT NULL, 
    name VARCHAR(100), 
    chief_id INTEGER, 
    parent_department_id INTEGER, 
    PRIMARY KEY (department_id), 
    UNIQUE (name), 
    FOREIGN KEY(parent_department_id) REFERENCES departments (department_id)
)

2011-03-24 15:09:58,312 INFO sqlalchemy.engine.base.Engine.0x...42cc ()
2011-03-24 15:09:58,312 INFO sqlalchemy.engine.base.Engine.0x...42cc COMMIT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接