sqlalchemy现有数据库查询

Dev*_*evC 14 python pylons sqlalchemy pyramid

我使用SQLAlchemy作为python项目的ORM.我创建了几个模型/架构,它工作正常.现在我需要查询现有的MySQL数据库,不需要插入/更新select语句.

如何围绕此现有数据库的表创建包装器?我简要介绍了sqlalchemy文档和SO,但找不到任何相关内容.所有建议执行方法,我需要编写原始sql查询,而我想使用SQLAlchemy查询方法,就像我使用SA模型一样.

例如,如果现有的db具有表名User,那么我想使用dbsession查询它(只有select操作,可能是使用join)

Ser*_*gey 11

您似乎有一种印象,即SQLAlchemy只能使用SQLAlchemy创建的数据库结构(可能使用MetaData.create_all()) - 这是不正确的.SQLAlchemy可以与预先存在的数据库完美配合,您只需要定义模型以匹配数据库表.一种方法是使用反射,正如IljaEverilä建议的那样:

class MyClass(Base):
    __table__ = Table('mytable', Base.metadata,
                    autoload=True, autoload_with=some_engine)
Run Code Online (Sandbox Code Playgroud)

(在我看来,这对于一次性脚本来说完全没问题,但如果数据库结构可能会随着时间的推移发生变化,可能会导致"真实"应用程序中出现令人难以置信的令人沮丧的错误)

另一种方法是像往常一样简单地定义模型,注意定义模型以匹配数据库表,这并不困难.这种方法的好处是,您只能将数据库表的子集映射到模型,甚至只能将表列的子集映射到模型的字段.假设您在数据库中有10个表,但只对users您需要的表感兴趣id,name并且email字段:

class User(Base):
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String)
    email = sa.Column(sa.String)
Run Code Online (Sandbox Code Playgroud)

(注意我们不需要定义一些只需要发出正确DDL的细节,例如字符串字段的长度或email字段有索引的事实)

除非您在代码中创建或修改模型,否则SQLAlchemy不会发出INSERT/UPDATE查询.如果要确保查询是只读的,可以在数据库中创建特殊用户,并仅授予该用户SELECT权限.或者/此外,您还可以尝试在应用程序代码中回滚事务.

  • @Sergey,您能添加所有进口吗? (4认同)
  • @Sergey是的,进口可能很重要(双关语)。 (4认同)

Ran*_*ani 6

您可以使用自动映射扩展名访问现有表:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session

Base = automap_base()
Base.prepare(engine, reflect=True)

Users = Base.classes.users
session = Session(engine)

res = session.query(Users).first()
Run Code Online (Sandbox Code Playgroud)


Gri*_*ave 6

带有一些示例代码:

from sqlalchemy.sql import select
from sqlalchemy import create_engine, MetaData, Table

CONN_STR = '…'
engine = create_engine(CONN_STR, echo=True)
metadata = MetaData()
cookies = Table('cookies', metadata, autoload=True,
                           autoload_with=engine)
cols = cookies.c


with engine.connect() as conn:

    query = (
        select([cols.created_at, cols.name])
                .order_by(cols.created_at)
                .limit(1)
    )
    for row in conn.execute(query):
        print(row)
Run Code Online (Sandbox Code Playgroud)

  • `autoload` 已在 1.4 中弃用 (https://docs.sqlalchemy.org/en/14/core/metadata.html?highlight=autoload#sqlalchemy.schema.Table.params.autoload)。使用“autoload_with”。 (4认同)