I'm using turboears 0.9a5 and sqlalchemy 0.1.6. Recently, I decided to
upgrade everything to latest version.
However there are some problems. Specifically, all my applications are
connecting to more than one database. Apparently, support for multiple
databases is no longer as good as it was (partially because of changes
in SA). Before there was objectstore which handled all details, but now
that it is gone, turbogears has mostly lost it's support for multiple
SA databases.
First issue is that turbogears decides if SA is active like this:
def _use_sa():
return _engine is not None
where _engine is globaly initialized using "sqlalchemy.dburi" config
key.
I don't have "sqlalchemy.dburi". Instead, I have:
isoz.sqlalchemy.dburi
tool.sqlalchemy.dburi
dialer.sqlalchemy.dburi
sugarcrm.sqlalchemy.dburi
My proposal is to decide if SA is active like this:
config.get("sqlalchemy.in_use", False)
and to somewhere (there is an example later) active it like this:
config.update({"sqlalchemy.in_use" : True})
Second issue is that turbogears supports PackageHub's for SQLObject and
there is no similar facility for SA. Direct result of this is that
there is ONE global engine (via sqlalchemy.dburi) and one global
metadata. It even goes that far as to replace activemapper's metadata
with that global object.
Also there is a bind_meta_data() function which has to be called from
several locations to make all this work (startup.py, command/base.py,
visit\savisit.py). It would be easier to use autoconnecting
engine/metadata.
This is my attempt to (partially) solve turbogears support for multiple
SA databases. It should replace similar block from database.py:
try:
import sqlalchemy
from sqlalchemy.ext import activemapper
from sqlalchemy.ext.proxy import AutoConnectEngine
class TurboMetaData(object):
def __init__(self):
# Dictionary of all package metadata objects
# Key is:
# * package name in case of package uri
(<name>.sqlalchemy.dburi)
# * None in case of default database (sqlalchemy.dburi)
self.metadatas = {}
# If there is a main sqlalchemy uri, replace default
metadata in activemapper
if config.get("sqlalchemy.dburi", None):
activemapper.metadata = SAPackageMetaData()
def __getattr__(self, name):
try:
return self.metadatas[name]
except KeyError:
return getattr(self.metadatas[None], name)
metadata = TurboMetaData() #activemapper.metadata
session = activemapper.objectstore
def bind_meta_data():
pass # Everything is already bound when using SAPackageMetaData
def create_engine(*args, **kwargs):
"""Used to create package engines when no override is
specified.
Can be patched from user code
"""
return SAPackageEngine(*args, **kwargs)
class SAPackageEngine(AutoConnectEngine):
"""
An AutoConnectEngine that looks for the dburi based on a
package name.
You can also create AutoConnectEngine as you would and other
engine: by
specifying dburi and dict of parameters.
"""
def __init__(self, packagename_or_dburi, **kwargs):
dburi = self.get_dburi(packagename_or_dburi)
super(SAPackageEngine, self).__init__(dburi, **kwargs)
def get_dburi(self, packagename_or_dburi):
if packagename_or_dburi:
return config.get("%s.sqlalchemy.dburi" %
packagename_or_dburi, packagename_or_dburi)
else:
return config.get("sqlalchemy.dburi", None)
class SAPackageMetaData(sqlalchemy.BoundMetaData):
"""
An autoconnecting metadata intended to be used on package
level.
"""
def __init__(self, engine_or_url=None, engine_creator=None,
name=None, **kwargs):
if isinstance(engine_or_url, basestring) or engine_or_url
is None:
creator = engine_creator or create_engine
engine = creator(engine_or_url, **kwargs)
name = name or engine_or_url
else:
engine = engine_or_url
super(SAPackageMetaData, self).__init__(engine, name=name,
**kwargs)
name = self.name or engine_or_url
metadata.metadatas[name] = self
config.update({"sqlalchemy.in_use" : True})
global _engine
_engine = True # to fool _use_sa()
except ImportError:
sqlalchemy = None
To use is you have to do something like this:
from sqlalchemy import *
from sqlalchemy.ext.activemapper import *
from turbogears.database import SAPackageMetaData
__metadata__ = SAPackageMetaData('mypkg', echo=True,
encoding='windows-1250')
class Test(ActiveMapper):
class mapping:
__table__ = 'test'
id = column(Integer, primary_key=True)
name = column(Unicode(100))
desc = column(Unicode(255))
I would welcome any comments on how to handle multiple databases,
especially if such support is not planned in turbogears.
Regards,
Tvrtko
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"TurboGears" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/turbogears
-~----------~----~----~----~------~----~------~--~---