Multiple projects with seperate databases for the same db-model

65 views
Skip to first unread message

Kai H.

unread,
Jul 26, 2012, 12:20:20 PM7/26/12
to turbo...@googlegroups.com
Hello,

i'm trying to make my TG2-App be able to handle several projects, i.e. several database-instances for the same db-model (including user-tables for authentication).  They should be accessed by:
http://localhost:8080/project1
http://localhost:8080/project2 etc.

At the moment i have something like this in my development/whatever.ini

sqlalchemy.project1.url= mysql://foo:bar@host1:3306/project1
sqlalchemy.project2.url = mysql://foo:bar@host2:3306/project2

for project-access in my root-controller i have sth. like

@expose()
def _lookup(self, project, *remainder):
    engine = engine_from_config(pylons_config, 'sqlalchemy.%s.' % project)
    app_globals.project = project
    DBSession.configure(bind=engine)      
    project = RootProjectController()
    return project, remainder

That works actually pretty well, except for the authentication (standard-tg2). And that is my problem. I tried to bend the login-stuff (like the login_handler) to \project1\login_handler, but i didnt manage to get it working.

Do you have any suggestions how to get the login working under /project/login?
OR do you have any other suggestions for that multi-project-problem?

Thanks in advance,
Kai

Alessandro Molina

unread,
Jul 26, 2012, 2:53:19 PM7/26/12
to turbo...@googlegroups.com
Subclass the sqlalchemy.orm.Session providing a get_bind method, then
you can pass the class_ parameter to the sessionmaker inside
model/__init__.py

Whenever the session is going to be used the get_bind method will be
called to ask for the bound engine, so you can implement there any
logic to return different engines and so route to multiple databases.
> --
> You received this message because you are subscribed to the Google Groups
> "TurboGears" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/turbogears/-/Ci5cJoxDDSIJ.
> To post to this group, send email to turbo...@googlegroups.com.
> To unsubscribe from this group, send email to
> turbogears+...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/turbogears?hl=en.
Message has been deleted

Alessandro Molina

unread,
Oct 16, 2012, 3:25:24 AM10/16/12
to turbo...@googlegroups.com
Yes, that's because the auth happens before the tg.request object has
been registered, so you cannot rely on it to decide the database so
use.
You can check if a request is not available and in that case always
use a default engine, otherwise working around this issue is much
bigger.

I'm looking for a solution to this in the upcoming tg release, but for
2.2 there isn't currently any quick work-around I'm aware of, the Auth
stack is simply before the request object due to how Pylons worked.


On Tue, Oct 16, 2012 at 1:07 AM, Kai H. <kai.hil...@gmail.com> wrote:
> Hey Allessandro
>
> Am Donnerstag, 26. Juli 2012 20:53:19 UTC+2 schrieb Alessandro Molina:
>>
>> Subclass the sqlalchemy.orm.Session providing a get_bind method, then
>> you can pass the class_ parameter to the sessionmaker inside
>> model/__init__.py
>>
>> Whenever the session is going to be used the get_bind method will be
>> called to ask for the bound engine, so you can implement there any
>> logic to return different engines and so route to multiple databases.
>
>
> First of all: Thank you very much. I followed your advice and it works so
> far.
>
> But i have a problem anyway. In the get_bind-logic i want to return the
> engine depending on the requested URL.
> At the moment i use request.environ['PATH_INFO'], but for some
> get_bind()-calls i got the Exception below when i try to access tg.request
> (and when i dont catch it). In those cases i cannot determine the DB-Engine
> by path.
>
> Do you have a hint? Can i maybe access the request-URL on a lower level?
>
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/WebError-0.10.3-py2.6.egg/weberror/evalexception.py',
>> line 431 in respond
>> app_iter = self.application(environ, detect_start_response)
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/TurboGears2-2.2.0-py2.6.egg/tg/configuration/app_config.py',
>> line 894 in remover
>> return app(environ, start_response)
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/repoze.tm2-1.0-py2.6.egg/repoze/tm/__init__.py',
>> line 24 in __call__
>> result = self.application(environ, save_status_and_headers)
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/repoze.who-2.0-py2.6.egg/repoze/who/middleware.py',
>> line 76 in __call__
>> identity = api.authenticate()
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/repoze.who-2.0-py2.6.egg/repoze/who/api.py',
>> line 151 in authenticate
>> self._add_metadata(identity)
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/repoze.who-2.0-py2.6.egg/repoze/who/api.py',
>> line 367 in _add_metadata
>> plugin.add_metadata(self.environ, identity)
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/TurboGears2-2.2.0-py2.6.egg/tg/configuration/auth.py',
>> line 51 in add_metadata
>> identity['user'] = self.tgmdprovider.get_user(identity, userid)
>> File '/home/whatever/workspace/tg22env/myapp/myapp/config/app_cfg.py',
>> line 92 in get_user
>> return
>> self.sa_auth.dbsession.query(self.sa_auth.user_class).filter_by(user_name=userid).first()
>> File 'build/bdist.linux-x86_64/egg/sqlalchemy/orm/query.py', line 2156 in
>> first
>> File 'build/bdist.linux-x86_64/egg/sqlalchemy/orm/query.py', line 2023 in
>> __getitem__
>> File 'build/bdist.linux-x86_64/egg/sqlalchemy/orm/query.py', line 2227 in
>> __iter__
>> File 'build/bdist.linux-x86_64/egg/sqlalchemy/orm/query.py', line 2240 in
>> _execute_and_instances
>> File 'build/bdist.linux-x86_64/egg/sqlalchemy/orm/query.py', line 2231 in
>> _connection_from_session
>> File 'build/bdist.linux-x86_64/egg/sqlalchemy/orm/session.py', line 727 in
>> connection
>> File '/home/whatever/workspace/tg22env/myapp/myapp/lib/mysession.py', line
>> 22 in get_bind
>> print request.environ['PATH_INFO']
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/registry.py',
>> line 137 in __getattr__
>> return getattr(self._current_obj(), attr)
>> File
>> '/home/whatever/workspace/tg22env/lib/python2.6/site-packages/Paste-1.7.5.1-py2.6.egg/paste/registry.py',
>> line 197 in _current_obj
>> 'thread' % self.____name__)
>> TypeError: No object (name: request) has been registered for this thread
>
>
>
> Thanks in advance,
> Kai
>
> --
> You received this message because you are subscribed to the Google Groups
> "TurboGears" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/turbogears/-/Ne5mPTvTLgUJ.
Reply all
Reply to author
Forward
0 new messages