Pylons 中具有自动加载(反射)功能的 SQLAlchemy 声明性语法

问题描述 投票:0回答:5

我想使用自动加载来使用现有数据库。我知道如何在没有声明性语法的情况下做到这一点(model/_init_.py):

def init_model(engine):
    """Call me before using any of the tables or classes in the model"""
    t_events = Table('events', Base.metadata, schema='events', autoload=True, autoload_with=engine)
    orm.mapper(Event, t_events)

    Session.configure(bind=engine)  

class Event(object):
    pass

这工作正常,但我想使用声明性语法:

class Event(Base):
    __tablename__ = 'events'
    __table_args__ = {'schema': 'events', 'autoload': True}

不幸的是,这样我得到:

sqlalchemy.exc.UnboundExecutionError:没有引擎绑定到该表的元数据。通过 autoload_with= 将引擎传递给表,或通过metadata.bind=

将元数据与引擎关联

这里的问题是,在导入模型的阶段(在 init_model() 中可用),我不知道从哪里获取引擎(在 autoload_with 中使用它)。我尝试添加

meta.Base.metadata.bind(engine)

到environment.py,但它不起作用。有人找到了一些优雅的解决方案吗?

python reflection sqlalchemy pylons declarative
5个回答
12
投票

好吧,我想我明白了。解决方案是在

model/__init__.py
之外声明模型对象。我得出的结论是,当从模块导入某些内容时(在本例中为
__init__.py
),
model
会作为第一个文件导入,这会导致问题,因为模型对象是在调用
init_model()
之前声明的。

为了避免这种情况,我在

model
模块中创建了一个新文件,例如
objects.py
。然后我在此文件中声明了所有模型对象(如
Event
)。

然后,我可以像这样导入我的模型:

from PRJ.model.objects import Event

此外,为了避免为每个表指定

autoload-with
,我在
init_model()
的末尾添加了这一行:

Base.metadata.bind = engine

这样我就可以声明我的模型对象而无需样板代码,如下所示:

class Event(Base):
    __tablename__ = 'events'
    __table_args__ = {'schema': 'events', 'autoload': True}

    event_identifiers = relationship(EventIdentifier)

    def __repr__(self):
        return "<Event(%s)>" % self.id

1
投票

我刚刚使用 orm 模块尝试过这个。

Base = declarative_base(bind=engine)

Base.metadata.reflect(bind=engine)

手动或通过循环或其他方式访问表:

Base.metadata.sorted_tables

可能有用。


0
投票

查看将 SQLAlchemy 与 Pylons 一起使用教程,了解如何在

init_model
函数中将元数据绑定到引擎。

如果

meta.Base.metadata.bind(engine)
语句成功将模型元数据绑定到引擎,您应该能够在自己的
init_model
函数中执行此初始化。我猜你并不是想跳过这个函数中的元数据绑定,是吗?


0
投票
from sqlalchemy import MetaData,create_engine,Table
engine = create_engine('postgresql://postgres:********@localhost/db_name')

metadata = MetaData(bind=engine)

rivers = Table('rivers',metadata,autoload=True,auto_load_with=engine)

from sqlalchemy import select

s = select([rivers]).limit(5)
engine.execute(s).fetchall()

为我工作。我收到错误是因为在创建

MetaData()
对象时未指定绑定。


0
投票

为旧问题提供更新的答案。

尽管原始答案中的方法效果很好,但

sqlalchemy
文档中推荐的方法是不同的

根据文档。

  1. 创建引擎
  2. 创建基类
  3. 在基类的
    reflect()
    对象上调用
    metadata
    方法
  4. 创建表类并将适当的反映表分配给该类的
    __table__
    属性

这是代码

import sqlalchemy as sql

engine = sql.orm.create_engine("postgresql+psycopg2://user:pass@hostname/my_existing_database")

class Base(sql.orm.DeclarativeBase): 
    pass


Base.metadata.reflect(engine)

class MyClass(Base):
    __table__ = Base.metadata.tables["mytable"]

参考资料:

https://docs.sqlalchemy.org/en/20/orm/declarative_tables.html#orm-declarative-reflected

© www.soinside.com 2019 - 2024. All rights reserved.