On Sat, May 23, 2009 at 3:18 AM, Benjamin A. Shelton
<[email protected]> wrote:
>
> As an addendum to my previous posts, here is a run-through on my
> solution for anyone who might encounter a similar problem at a future
> date.
>
> ***Disclaimer: I don't think this is the best solution, but it seemed
> to work for me.***
>
After reading this it actually isn't that crazy :) I also have had the
issue of using the config on module loading. Where you able to run the
test suite to this and things work fine? I'll love to see a patch so
we can test it. If it has no side effects I think it's the way to go.
Config should be available everywhere.

> Brief background: I need to write an application that may potentially
> live in the same database as another app, both running under MySQL.
> Hence, it is necessary to generate tables for my TG2 project that
> include a user-configurable prefix in the project .ini files.
>
> First, I tried using metaclasses to resolve the issue of having to
> tack on a __tablename__ to each object in my app's model. This didn't
> work, and I found out why. In SQLAlchemy, the declarative_base()
> function returns a class that itself is already generated from a
> metaclass. The result is that you're left with an error message (one
> that is almost comical if you imagine it spoken as a sage's riddle)
> along the lines of:
>
As for this particular problem I think what you need is to ask in the
SA list to see if this can be patched in. The idea behind
DeclarativeBase being a function instead of a class is to make it
flexible which is exactly what you want right now.

Right now you should be able to do something like this.

def yourCustomConstructor(self, **kwargs):
    self.__tablename__ = config.get("database.table.prefix") +
self.__tablename__
    _declarative_constructor()

DeclarativeBase = declarativeBase(constructor=yourCustomConstructor)

Since this is a very common use case (at least from people coming from
the php world) I think the ideal solution will be to have

DeclarativeBase = declarativeBase(prefix=config.get("database.table.prefix"))

and a patch to handle the fact near like 460 of /sqlalchemy/ext/declarative.py

That said I know you can do some mapper tricks to also accomplish this.


> metaclass conflict: the metaclass of a derived class must be a
> (non-strict) subclass of the metaclasses of all its bases
>
> Thus, I stuck with my original consideration of doing something like:
>
> '''
> class User (DeclarativeBase):
>    __tablename__ = config.get("database.table.prefix") + "users"
> '''
>
> This is a little extra work since it needs to be added to each table
> in the model. It isn't elegant, and when I get a little extra time
> I'll see if there's something else I can do along the lines of
> Gustavo's suggestions. (I still think some derivation of that would
> work.)
>
> Second, since I wanted the table prefix to be configurable from the
> project .ini files, there was the issue of being unable to use
> config.get() "out of the box," so to speak. Since the model module has
> to be imported well before the "global_conf" is merged into it (or I
> guess that's local_conf or app_conf, depending on context!), trying to
> use the config object doesn't work without some project changes. I did
> some introspection into TG2's configuration module and figured that if
> I could tweak the module loading order (in my project) it would work.
> So far, so good. Here's what I had to do:
>
> I first set up a global module that would hold the application
> configs. I could've used the Globals object, and I'll probably make
> changes using it instead as this was a quick hack. As such, a simple
> module along the lines of:
>
> '''
> from tg.configuration import Bunch
>
> locals = {}
> def update_locals (config):
>    global locals
>    locals = Bunch(config)
> '''
>
> Does nicely. Using the global statement makes me feel kind of dirty, however.
>
> Next, under config/middleware.py, I moved these statements:
>
> '''
> from projectname.config.app_cfg import base_config
> from projectname.config.environment import load_environment
> make_base_app = base_config.setup_tg_wsgi_app(load_environment)
> '''
>
> Into the make_app() function. These were placed AFTER doing something like:
>
> '''
> from projectname.config.local_config import update_locals
> update_locals(app_conf)
> '''
>
> Which gives the application time to examine the configs sent to it
> from the environment (paster, etc) before the model is loaded.
>
> I did something similar to websetup.py so the ``paster setup-app
> [projectphase].ini`` would work, too.
>
> So far, I've tested this with a quickstart generated TG2 project (with
> authentication) using paster and mod_wsgi. It seems to work, prefixes
> and all. I can't help but feel this is a blasphemous abuse of the
> templates quickstart generates for us, though... So, I apologize for
> both a lengthy follow-up *and* my blatant abuse of TG2's quickstart
> templates. :)
>
> Thanks, everyone, for your help!
>
> --
> Regards,
> Benjamin
>
> >
>

--~--~---------~--~----~------------~-------~--~----~
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?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to