如何在Python的模块级initialize()方法中动态创建类



我正在编写一个使用SQLAlchemy与数据库通信的库。我非常喜欢SQLAlchemy的autoload_with=engine特性,它可以传递给Table构造函数来获取表的所有列,而程序员不必显式地定义它们。

下面是一个名为"something"的表的基本方法:

Base = declarative_base()
engine = create_engine('mysql://user:pass@host/db_name')
table = Table('something', Base.metadata, autoload_with=engine)
class Something(Base):
    __table__ = table

然而,我们有多个版本的数据库(在不同的主机上),所以我需要我的引擎在运行时作为参数传入。我有点讨厌在我的模块中写这样的东西,但我有一个更好的方法:

Base = declarative_base()
Something = None   # gets defined after initialize() is called
def initialize(engine):
    table = Table('something', Base.metadata, autoload_with=engine)
    class _Something(Base):
        __table__ = table
    global Something
    Something = _Something

在使用SQLAlchemy模型之前,客户端代码必须做一些讨厌的事情:

import custom_db_api
engine = create_engine(...)
custom_db_api.initialize(engine)
有没有更好的方法来处理这种由外部调用者进行的模块初始化?

嗯,您必须找到一些方法将engine变量传递给custom_db_api模块。这可能稍微干净一点…

Base = declarative_base()
class Something(Base):
    pass
def initialize(engine):
    Something.__table__ = Table('something', Base.metadata, autoload_with=engine)

…或者如果你可以从一些"全局"中推断出正确的引擎初始化参数,比如sys.argv,你可以使用这样的东西…

import sys
Base = declarative_base()
if len(sys.argv) > 1 and sys.argv[1] == '--use-alt-db':
    engine = create_engine('mysql://user:pass@alt_host/db_name')
else:
    engine = create_engine('mysql://user:pass@main_host/db_name')
table = Table('something', Base.metadata, autoload_with=engine)
class Something(Base):
    __table__ = table

这有点取决于你打算如何告诉程序使用哪个数据库。

相关内容

  • 没有找到相关文章

最新更新