【问题标题】:SQLAlchemy declarative syntax with autoload (reflection) in PylonsPylons 中带有自动加载(反射)的 SQLAlchemy 声明性语法
【发布时间】:2011-05-30 09:59:08
【问题描述】:

我想使用自动加载来使用现有数据库。我知道如何在没有声明性语法的情况下做到这一点 (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= 将引擎传递给 Table,或通过 metadata.bind=

将 MetaData 与引擎关联

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

meta.Base.metadata.bind(engine)

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

【问题讨论】:

    标签: python reflection sqlalchemy pylons declarative


    【解决方案1】:

    好吧,我想我明白了。解决方案是在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
    

    【讨论】:

      【解决方案2】:

      我刚刚尝试使用 orm 模块。

      Base = declarative_base(bind=engine)
      
      Base.metadata.reflect(bind=engine)
      

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

      Base.metadata.sorted_tables
      

      可能有用。

      【讨论】:

        【解决方案3】:

        查看Using SQLAlchemy with Pylons tutorial,了解如何在init_model 函数中将元数据绑定到引擎。

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

        【讨论】:

        • 这不是最新的。你说的是这条线:meta.engine = engine,对吧? Pylons 1.0 在 meta 模块中甚至没有任何 engine 变量...更不用说在编写本教程时,声明性语法不存在。
        • 你是对的,但我的意思是在init_model 中将元数据绑定到引擎,尽管与最新版本的实现存在差异。你明白了。如果您在init_model 中执行Base.metadata.bind(engine),它不起作用吗?您也可以按照您收到的错误消息的建议在init_model 中尝试Base.metadata.bind = engine
        • 它不起作用,因为 init_model() 在模型已经创建之后被调用。模型是在执行from PRJ.model import init_model 时创建的(它从模块中导入一些东西,因此所有模块都被执行),即在调用 init_model() 之前。
        • 我看到你想通了。抱歉,如果我没有从一开始就让自己完全清楚。我不知道你在 model/__init__.py 中声明模型类,所以我不明白为什么你不能在声明模型类之前调用​​ init_model
        • 我明白了,没问题,可能是我说的不够清楚。无论如何感谢您的回答。
        【解决方案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() 对象时未指定绑定,我收到错误消息。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-23
          • 2011-02-08
          • 1970-01-01
          • 2011-12-02
          相关资源
          最近更新 更多