Pylons中使用SQLAlchemy声明语法与自动加载(反射)
我想用自动加载功能来使用一个已经存在的数据库。我知道怎么在不使用声明式语法的情况下做到这一点(在 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=<someengine> 将引擎传递给这个表,或者通过 metadata.bind=<someengine> 将元数据与引擎关联。
这里的问题是,我不知道从哪里获取引擎(以便在 autoload_with 中使用),因为在导入模型的时候它是不可用的(它在 init_model() 中可用)。我尝试在 environment.py 中添加
meta.Base.metadata.bind(engine)
但这并没有奏效。有没有人找到什么优雅的解决方案?
4 个回答
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()
对象时没有指定绑定。
我刚刚尝试了一下使用orm模块。
Base = declarative_base(bind=engine)
Base.metadata.reflect(bind=engine)
手动访问表格,或者通过循环,或者其他方式:
Base.metadata.sorted_tables
这可能会很有用。
好的,我想我搞明白了。解决办法是把模型对象的声明放在 model/__init__.py
文件之外。我发现当从一个模块(在这个例子中是 model
)导入东西时,__init__.py
会被首先导入,这就会造成问题,因为模型对象在调用 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