使用SQLAlchemy MetaData获取现有表

dop*_*man 7 python sqlalchemy

我有一个已经存在的表:

USERS_TABLE = Table("users", META_DATA,
                    Column("id", Integer, Sequence("user_id_seq"), primary_key=True),
                    Column("first_name", String(255)),
                    Column("last_name", String(255))
                   )
Run Code Online (Sandbox Code Playgroud)

我通过运行这个创建了这个表:

CONN = create_engine(DB_URL, client_encoding="UTF-8")
META_DATA = MetaData(bind=CONN, reflect=True)
# ... table code
META_DATA.create_all(CONN, checkfirst=True)
Run Code Online (Sandbox Code Playgroud)

它第一次工作,我能够创建表.但是,第二次我遇到了这个错误:

sqlalchemy.exc.InvalidRequestError: Table 'users' is already defined for this MetaData instance.  Specify 'extend_existing=True' to redefine options and columns on an existing Table object.
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为该表users已经存在.我能够看到表是否存在如下:

TABLE_EXISTS = CONN.dialect.has_table(CONN, "users")
Run Code Online (Sandbox Code Playgroud)

但是,我如何实际获取现有的表对象?我在文档中的任何地方都找不到这个.请帮忙.

Aza*_*kov 13

我们在这里有3种不同的方法:

  • 假设已经创建了所需的表,反映它们并使用MetaData.tables字典字段

    from sqlalchemy import MetaData, create_engine
    
    CONN = create_engine(DB_URL, client_encoding="UTF-8")
    
    META_DATA = MetaData(bind=CONN, reflect=True)
    
    USERS_TABLE = META_DATA.tables['users']
    
    Run Code Online (Sandbox Code Playgroud)
  • reflectMetaData对象初始化中删除标志,因为我们不使用它而且 - 尝试创建已经反映的表:

    from sqlalchemy import MetaData, Table, Column, Integer, String, Sequence, create_engine
    
    CONN = create_engine('sqlite:///db.sql')
    
    META_DATA = MetaData(bind=CONN)
    
    USERS_TABLE = Table("users", META_DATA,
                        Column("id", Integer, Sequence("user_id_seq"), primary_key=True),
                        Column("first_name", String(255)),
                        Column("last_name", String(255))
                        )
    
    META_DATA.create_all(CONN, checkfirst=True)
    
    Run Code Online (Sandbox Code Playgroud)
  • 假设我们保留了反射表,如果之前通过将Table对象初始化程序keep_existing标志设置为True:

    from sqlalchemy import MetaData, Table, Column, Integer, String, Sequence, create_engine
    
    CONN = create_engine('sqlite:///db.sql')
    
    META_DATA = MetaData(bind=CONN, reflect=True)
    
    USERS_TABLE = Table("users", META_DATA,
                        Column("id", Integer, Sequence("user_id_seq"), primary_key=True),
                        Column("first_name", String(255)),
                        Column("last_name", String(255)),
                        keep_existing=True
                        )
    
    META_DATA.create_all(CONN, checkfirst=True)
    
    Run Code Online (Sandbox Code Playgroud)

哪一个选择?取决于你的用例,但我更喜欢第二个,因为它看起来你没有使用反射,也是最简单的修改:只是从MetaData初始化程序中删除标志.


PS

我们总是可以在MetaData使用MetaData.reflect方法初始化对象后进行反射:

META_DATA.reflect()
Run Code Online (Sandbox Code Playgroud)

我们也可以指定哪些表用only参数反映(可以是任何可迭代str对象):

META_DATA.reflect(only=['users'])
Run Code Online (Sandbox Code Playgroud)

许多更多.


Ami*_*hak 8

这对我来说非常有效 -

import sqlalchemy as db

engine = db.create_engine("your_connection_string")

meta_data = db.MetaData(bind=engine)
db.MetaData.reflect(meta_data)

USERS = meta_data.tables['users']

# View the columns present in the users table
print(USERS.columns)

# You can run sqlalchemy queries
query = db.select([
    USERS.c.id,
    USERS.c.first_name,
    USERS.c.last_name,
])

result = engine.execute(query).fetchall()
Run Code Online (Sandbox Code Playgroud)

请注意,不推荐使用reflect参数 in Metadata(bind=engine, reflect=True),并将在未来版本中删除。上面的代码就解决了这个问题。