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

发布于 2024-10-08 22:07:45 字数 960 浏览 0 评论 0原文

我想使用自动加载来使用现有数据库。我知道如何在没有声明性语法的情况下做到这一点(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=将元数据与引擎关联起来

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

meta.Base.metadata.bind(engine)

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

I would like to use autoload to use an existings database. I know how to do it without declarative syntax (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

This works fine, but I would like to use declarative syntax:

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

Unfortunately, this way I get:

sqlalchemy.exc.UnboundExecutionError: No engine is bound to this Table's MetaData. Pass an engine to the Table via autoload_with=<someengine>, or associate the MetaData with an engine via metadata.bind=<someengine>

The problem here is that I don't know where to get the engine from (to use it in autoload_with) at the stage of importing the model (it's available in init_model()). I tried adding

meta.Base.metadata.bind(engine)

to environment.py but it doesn't work. Anyone has found some elegant solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

油饼 2024-10-15 22:07:45

好吧,我想我已经明白了。解决方案是在 model/__init__.py 之外声明模型对象。我得出的结论是,当从模块(在本例中为 model)导入某些内容时,__init__.py 会作为第一个文件导入,这会导致问题,因为模型对象是在 < code>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

OK, I think I figured it out. The solution is to declare the model objects outside the model/__init__.py. I concluded that __init__.py gets imported as the first file when importing something from a module (in this case model) and this causes problems because the model objects are declared before init_model() is called.

To avoid this I created a new file in the model module, e.g. objects.py. I then declared all my model objects (like Event) in this file.

Then, I can import my models like this:

from PRJ.model.objects import Event

Furthermore, to avoid specifying autoload-with for each table, I added this line at the end of init_model():

Base.metadata.bind = engine

This way I can declare my model objects with no boilerplate code, like this:

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

    event_identifiers = relationship(EventIdentifier)

    def __repr__(self):
        return "<Event(%s)>" % self.id
耳钉梦 2024-10-15 22:07:45

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

Base = declarative_base(bind=engine)

Base.metadata.reflect(bind=engine)

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

Base.metadata.sorted_tables

可能有用。

I just tried this using orm module.

Base = declarative_base(bind=engine)

Base.metadata.reflect(bind=engine)

Accessing tables manually or through loop or whatever:

Base.metadata.sorted_tables

Might be useful.

暖阳 2024-10-15 22:07:45

查看将 SQLAlchemy 与 Pylons 结合使用教程如何在 init_model 函数中将元数据绑定到引擎。

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

Check out the Using SQLAlchemy with Pylons tutorial on how to bind metadata to the engine in the init_model function.

If the meta.Base.metadata.bind(engine) statement successfully binds your model metadata to the engine, you should be able to perform this initialization in your own init_model function. I guess you didn't mean to skip the metadata binding in this function, did you?

栀子花开つ 2024-10-15 22:07:45
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() 对象时未指定绑定。

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()

worked for me. I was getting the error because of not specifying bind when creating MetaData() object.

熟人话多 2024-10-15 22:07:45

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

尽管原始答案中的方法效果很好,但 sqlalchemy 文档中推荐的方法

根据文档的不同而有所不同。

  1. 创建引擎
  2. 创建基类
  3. 在基类的 metadata 对象上调用 reflect() 方法
  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

providing an updated answer to an old question.

Even though the method in the original answer works well the recommended approach in the sqlalchemy docs is different

according to the docs.

  1. Create the engine
  2. Create the Base class
  3. Call the reflect() method on your Base class's metadata object
  4. Create your table class and assign the appropriate reflected table to the class's __table__ attribute

Here is the code

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"]

refrences:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文