2010-09-03 7 views
6

Meine App verbindet sich mit mehreren Datenbanken mit einer ähnlichen Technik wie this. Es funktioniert, solange ich nicht versuche, auf verschiedene Datenbanken in derselben Anfrage zuzugreifen. blickte zurück auf die obige Skript Nachdem ich sehe, sie haben einen Kommentar zu diesem Zweck geschrieben:Wie kann ich mehrere Datenbanken in der gleichen Anfrage in Cherrypy und SQLAlchemy verwenden?

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

Meine App jetzt verlangt, dass ich Daten aus der Datenbank A und Datenbank B zu holen Ist es möglich, diese in einer einzigen Anfrage zu tun ?

Bitte siehe unten für Quellen und Beispiele:

Arbeitsbeispiel 1:

from model import meta 

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

Arbeitsbeispiel 2:

from model import meta 

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

Fehler Beispiel:

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() 

Diese Fehler mit:

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

Quellen:

# 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

Ich möchte nicht meine eigene Frage "beantworten", aber die Lösung scheint zu sein, eine zusätzliche scoped_session für die andere Datenbank in 'connect' hinzuzufügen, so dass es aussieht wie' def connect (thread_index): cherrypy.thread_data.user_scoped_session_class = scooped_session (sessionmaker (autoflush = Wahr, autocommit = Falsch)) cherrypy.thread_data.main_scoped_session_class = scoped_session (sitemaker (autoflush = Wahr, autocommit = Falsch)) return 'und dann referenzieren sie separat in' open_dbsession' – OrganicPanda

Antwort

1

Sie könnten auch ein ORM wählen, die von Grund auf für mehrere Datenbanken, wie Dejavu ausgelegt ist.

0

Werfen Sie einen Blick auf diese:

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

Im Grunde ist es deutet darauf hin, dass Sie einen bind param verwenden - für jede Verbindung. Das scheint ein bisschen wie ein Hack zu sein.

Diese Frage hat viel mehr Detail in der Antwort:

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

Das heißt, beide diese Frage und derjenige verwiesen wird, sind nicht die neuesten und sqlalchemy wird seither wohl weitergegangen.

+0

Das sieht ziemlich gut aus. Am Ende stellte ich das unmittelbare Problem, mit dem ich konfrontiert war, mit dieser Frage (Siehe meinen der Frage beigefügten Kommentar), endete aber mit einigen weiteren Problemen; Es funktioniert jetzt alles, aber der Code und die dazugehörige Erklärung sind für StackOverflow viel zu groß. Mehrere Threads + mehrere dynamische DB-Verbindungen pro Benutzer + Auf-/Abbau pro Anfrage = Schmerz – OrganicPanda

Verwandte Themen