Question

I'm writing a library to talk to a database using SQLAlchemy. I really like SQLAlchemy's autoload_with=engine feature, which can be passed to the Table constructor to grab all of the table's columns without the programmer having to define them explicitly.

Here's the basic approach for a table named "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

However, we have multiple versions of our database (on different hosts) so I need my engine to be passed in as a parameter at runtime. I sort of hate the idea of writing something like this in my module, but I'm blanking on a better approach:

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

And then client code has to do something nasty like this before using any of the SQLAlchemy models:

import custom_db_api

engine = create_engine(...)
custom_db_api.initialize(engine)

Is there a better approach to handling this kind of module-initialization by an outside caller?

Was it helpful?

Solution

Well, you'll have to find some way to pass the engine variable to your custom_db_api module. This might be marginally cleaner...

Base = declarative_base()

class Something(Base):
    pass

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

...or if you can infer the correct engine initialization parameter from some 'global', like sys.argv, you could use something like this...

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

It kinda depends on how you intend to tell the program which DB to use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top