2010-09-03 19 views
6

Mi aplicación se conecta a múltiples bases de datos usando una técnica similar a this. Funciona siempre que no intente acceder a diferentes bases de datos en la misma solicitud. Después de examinar de nuevo a la secuencia de comandos que veo que han escrito un comentario para este fin:¿Cómo puedo usar varias bases de datos en la misma solicitud en Cherrypy y SQLAlchemy?

SQLAlchemy integration for CherryPy, 
such that you can access multiple databases, 
but only one of these databases per request or thread. 

Mi aplicación ahora me requiere para obtener los datos de la base de datos Una base de datos y B. ¿Es posible hacer esto en una sola petición ?

favor ver más abajo para las fuentes y ejemplos:

Ejemplo de Trabajo 1:

from model import meta 

my_object_instance = meta.main_session().query(MyObject).filter(
    MyObject.id == 1 
).one() 

de Trabajo Ejemplo 2:

from model import meta 

my_user = meta.user_session().query(User).filter(
    User.id == 1 
).one() 

Error Ejemplo:

from model import meta 

my_object_instance = meta.main_session().query(MyObject).filter(
    MyObject.id == 1 
).one() 

my_user = meta.user_session().query(User).filter(
    User.id == 1 
).one() 

Este errores con:

(sqlalchemy.exc.ProgrammingError) (1146, "Table 'main_db.user' doesn't exist") 

Fuentes:

# meta.py 
import cherrypy 
import sqlalchemy 
from sqlalchemy import MetaData 
from sqlalchemy.orm import scoped_session, sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 

# Return an Engine 
def create_engine(defaultschema = True, schema = "", **kwargs): 

    # A blank DB is the same as no DB so to specify a non-schema-specific connection just override with defaultschema = False 
    connectionString = 'mysql://%s:%[email protected]%s/%s?charset=utf8' % (
     store['application'].config['main']['database-server-config-username'], 
     store['application'].config['main']['database-server-config-password'], 
     store['application'].config['main']['database-server-config-host'], 
     store['application'].config['main']['database-server-config-defaultschema'] if defaultschema else schema 
    ) 
    # Create engine object. we pass **kwargs through so this call can be extended 
    return sqlalchemy.create_engine(connectionString, echo=True, pool_recycle=10, echo_pool=True, encoding='utf-8', **kwargs) 

# Engines 
main_engine = create_engine() 
user_engine = None 

# Sessions 
_main_session = None 
_user_session = None 

# Metadata 
main_metadata = MetaData() 
main_metadata.bind = main_engine 
user_metadata = MetaData() 

# No idea what bases are/do but nothing works without them 
main_base = declarative_base(metadata = main_metadata) 
user_base = declarative_base(metadata = user_metadata) 

# An easy collection of user database connections 
engines = {} 

# Each thread gets a session based on this object 
GlobalSession = scoped_session(sessionmaker(autoflush=True, autocommit=False, expire_on_commit=False)) 

def main_session(): 
    _main_session = cherrypy.request.main_dbsession 
    _main_session.configure(bind=main_engine) 

    return _main_session 

def user_session(): 
    _user_session = cherrypy.request.user_dbsession 
    _user_session.configure(bind = get_user_engine()) 

    return _user_session 

def get_user_engine(): 

    # Get dburi from the users instance 
    dburi = cherrypy.session['auth']['user'].instance.database 

    # Store this engine for future use 
    if dburi in engines: 
     engine = engines.get(dburi) 
    else: 
     engine = engines[dburi] = create_engine(defaultschema = False, schema = dburi) 

    # Return Engine 
    return engine 


def get_user_metadata(): 
    user_metadata.bind = get_user_engine() 
    return user_metadata 

# open a new session for the life of the request 
def open_dbsession(): 
    cherrypy.request.user_dbsession = cherrypy.thread_data.scoped_session_class 
    cherrypy.request.main_dbsession = cherrypy.thread_data.scoped_session_class 
    return 

# close the session for this request 
def close_dbsession(): 
    if hasattr(cherrypy.request, "user_dbsession"): 
     try: 
      cherrypy.request.user_dbsession.flush() 
      cherrypy.request.user_dbsession.remove() 
      del cherrypy.request.user_dbsession 
     except: 
      pass 
    if hasattr(cherrypy.request, "main_dbsession"): 
     try: 
      cherrypy.request.main_dbsession.flush() 
      cherrypy.request.main_dbsession.remove() 
      del cherrypy.request.main_dbsession 
     except: 
      pass 

    return 

# initialize the session factory class for the selected thread 
def connect(thread_index): 
    cherrypy.thread_data.scoped_session_class = scoped_session(sessionmaker(autoflush=True, autocommit=False)) 
    return 

# add the hooks to cherrypy 
cherrypy.tools.dbsession_open = cherrypy.Tool('on_start_resource', open_dbsession) 
cherrypy.tools.dbsession_close = cherrypy.Tool('on_end_resource', close_dbsession) 
cherrypy.engine.subscribe('start_thread', connect) 
+0

No quiero 'responder' mi propia pregunta pero la solución parece ser agregar una scoped_session extra para la otra base de datos en 'connect' para que parezca' def connect (thread_index): cherrypy.thread_data.user_scoped_session_class = scoped_session (sessionmaker (autoflush = True, autocommit = False)) cherrypy.thread_data.main_scoped_session_class = scoped_session (sessionmaker (autoflush = True, autocommit = False)) return' y luego los referencia por separado en 'open_dbsession' – OrganicPanda

Respuesta

1

También puede elegir un ORM que se ha diseñado desde cero para múltiples bases de datos, como Dejavu.

0

Tome un vistazo a esto:

http://pythonhosted.org/Flask-SQLAlchemy/binds.html

Básicamente, se sugiere el uso de un parámetro se unen - para cada conexión. Dicho esto, parece ser un truco.

Esta pregunta tiene mucho más detalle en la respuesta:

With sqlalchemy how to dynamically bind to database engine on a per-request basis

Dicho esto, tanto en esta pregunta y la que se hace referencia no son los más nuevos y sqlalchemy probablemente han cambiado desde entonces.

+0

Eso se ve bastante bien. Terminé arreglando el problema inmediato que estaba enfrentando con esta pregunta (ver mi comentario adjunto a la pregunta) pero terminé con varios problemas más; todo está funcionando ahora, pero el código y la explicación que lo acompañan son demasiado grandes para StackOverflow. Múltiples hilos + múltiples conexiones DB dinámicas por usuario + configuración/desmontaje por solicitud = dolor – OrganicPanda

Cuestiones relacionadas