Created
January 3, 2012 20:21
-
-
Save jvanasco/1556734 to your computer and use it in GitHub Desktop.
Reflecting in Pyramid/SqlAlchemy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
log = logging.getLogger(__name__) | |
from sqlalchemy import Table | |
from sqlalchemy import MetaData | |
from sqlalchemy.orm import mapper | |
from sqlalchemy.orm import scoped_session | |
from sqlalchemy.orm import sessionmaker | |
from zope.sqlalchemy import ZopeTransactionExtension | |
import app | |
import types | |
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) | |
DBMetadata = MetaData() | |
class ReflectedTable(object): | |
"""Base class for database objects that are mapped to tables by reflection. | |
Have your various model classes inherit from this class. If class.__tablename__ is defined, it will reflect | |
Example: | |
class Useraccount(ReflectedTable): | |
__tablename__ = "useraccount" | |
""" | |
__tablename__ = None | |
def map_tables( app_model ): | |
""" | |
""" | |
to_reflect = [] | |
for content in dir( app_model ): | |
module = getattr( app_model , content ) | |
if not isinstance( module , types.ModuleType ): | |
continue | |
for module_element in dir( module ): | |
module_element = getattr( module, module_element ) | |
if not isinstance( module_element , types.TypeType ): | |
continue | |
if issubclass( module_element , ReflectedTable ): | |
to_reflect.append( module_element ) | |
for _class in to_reflect: | |
table_name = _class.__tablename__ | |
if table_name: | |
log.info("Reflecting : %s (table: %s)" % (_class , table_name) ) | |
table= Table( table_name, DBMetadata, autoload=True ) | |
mapper( _class , table) | |
def initialize_sql(engine): | |
"""Call this once per engine from app.__init__.main | |
engine = sqlalchemy.engine_from_config(settings, prefix="sqlalchemy.") | |
sqlahelper.add_engine(engine) | |
models.initialize_sql(engine) | |
""" | |
log.debug( "\ninitialize_sql" ) | |
DBSession.configure(bind=engine) | |
DBMetadata.bind = engine | |
map_tables( app.models ) | |
## import various classes here. | |
import models_1 | |
import models_2 | |
import models_3 |
For future readers.. The DeferredReflection mixin is now built in to sqlaclehemy and should remove the need for special handling.
See docs here: http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative.html#using-reflection-with-declarative
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
yeah, the introspection is a bit ugly.
the reason why i decided to do it that way is that i've been refactoring a bunch of legacy code that i used as a 'bootstrap' module under pylons into pyramid - and splitting out the database portion of it
for the database code, i want to:
a_ reflect tables
b_ setup and manage multiple db handles ( read, write, log, etc )
right now, it looks more like this:
https://gist.github.com/1686834
ideally when I'm done , i'd do something like this:
i have at least 6 pylons apps that i'm migrating to pyramid, and am in the process of building 3 apps right now -- the more I can take stuff like this and abstract/simplify/standardize, the happier i am. the introspection is ugly, but its ultimately easier to migrate & easier to maintain.