2015-04-15 10 views
13

ho un "multi-tenant" Flask applicazione web che si interfaccia con 1 "master" database MySQL (utilizzato per cercare le informazioni del cliente) e decine di database MySQL "client" (che hanno tutti lo stesso schema).l'impostazione dinamica di connessione al database Flask-SQLAlchemy in multi-tenant app

Attualmente sto cercando di utilizzare SQLAlchemy insieme con l'estensione Flask-SQLAlchemy per interfacciarsi con i database, ma sto lottando per trovare un modo per consentire i modelli che definisco nella mia app per cambia dinamicamente il contesto da un database client a un altro, a seconda del client.

Sul Flask-SQLAlchemy site, un semplice esempio è mostrato lungo le linee di:

from flask import Flask 
from flask.ext.sqlalchemy import SQLAlchemy 

app = Flask(__name__) 
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:[email protected]/db1' 
db = SQLAlchemy(app) 

class User(db.Model): 
    # Etc. 

L'unico problema è, la configurazione SQLALCHEMY_DATABASE_URI avviene staticamente. Potrei dover cambiare tra mysql://username:[email protected]/db1 e mysql://username:[email protected]/db1 (o qualsiasi altro URI MySQL arbitrario), a seconda del client che sta effettuando la richiesta.

Ho trovato alcune domande simili (vedi sotto), ma devo ancora capire un modo pulito per farlo quando si utilizza l'estensione Flask-SQLAlchemy in particolare.

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

Flask SQLAlchemy setup dynamic URI

Ho visto anche alcuni esempi che sono stati forniti per la gestione di basi di dati sharded (che dovrebbero applicarsi pure, come i database sono essenzialmente sharded logicamente dal cliente), ma, ancora una volta, niente di specifico per Flask-SQLAlchemy.

Se ha senso, Sono anche aperto a utilizzare SQLAlchemy direttamente, senza l'estensione Flask-SQLAlchemy. Sono nuovo di SQLAlchemy - qualsiasi aiuto sarebbe molto apprezzato!

Modifica: Essere in grado di riflettere gli schemi di tabella dal database sarebbe un vantaggio.

+0

Avete visto http://stackoverflow.com/questions/7923966/flask-sqlalchemy-with-dynamic-database-connections e, in caso affermativo, quali ulteriori domande avete? –

+2

@SeanVieira Grazie - Ho appena controllato la risposta e sembra avere senso.Sto pensando di fare una sessione scopata per richiesta e di memorizzarla in 'flask.g'. Sono per lo più confuso su come impostare la classe stessa. Nell'esempio, 'Utente' è una sottoclasse di' db.Model', e 'db' è inizializzato da' SQLALCHEMY_DATABASE_URI'. Avrebbe ereditato 'User' da una classe base creata con' sqlalchemy.ext.declarative.declarative_base() 'o ci sarebbe un'altra classe che posso usare al posto di' db.Model 'di Flask-SQLAlchemy che non dipende su una specifica configurazione del database? – jstol

+0

Leggi questo: http://flask-sqlalchemy.pocoo.org/2.1/binds/ quindi dai un'occhiata a questo: https://gist.github.com/adhorn/b84dc47175259992d406. – ramabodhi

risposta

0

Si potrebbe fare qualcosa di simile. Per tua conoscenza questo è puro SQLAlchemy, non con Flask-SQLAlchemy. Si spera che ne abbiate bisogno per cose di sola lettura. Si può capire un po 'di altre cose da dover scrivere cose, come anche gli ascoltatori sul tuo sessione/modelli

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 

# an Engine, which the Session will use for connection 
# resources 
some_engine_1 = create_engine('postgresql://scott:[email protected]/') 
some_engine_2 = create_engine('postgresql://adriel:[email protected]/') 

# create a configured "Session" class 
Session_1 = sessionmaker(bind=some_engine_1) 
Session_2 = sessionmaker(bind=some_engine_2) 

# create a Session 
session_1 = Session_1() 
session_2 = Session_2() 

Base = declarative_base() 

class ModelBase(Base): 
    #different custom queries for each database 
    master_query = session_1.query_property() 
    client_1_query = session_2.query_property() 


class User(ModelBase): 
    pass 
    #ETC 


##Accessing the different databases: 
User.master_query.filter(User.id == 1).all() 
User.client_1_query.filter(User.id == 1).all() 
2

Se stai usando pallone-sqlalchemy 0,12 o poi, questa funzione è supportata con lega.

SQLALCHEMY_DATABASE_URI = 'postgres://localhost/main' 
SQLALCHEMY_BINDS = { 
'users':  'mysqldb://localhost/users', 
'appmeta':  'sqlite:////path/to/appmeta.db' 
} 

E è possibile specificare il database di connessione nella definizione del modello.

class User(db.Model): 
    __bind_key__ = 'users' 
    id = db.Column(db.Integer, primary_key=True) 
    username = db.Column(db.String(80), unique=True) 

Utilizzerà l'auto mysqldb. Per maggiori dettagli, è possibile consultare il documento ufficiale. Multiple Databases with Binds

+0

questa è la risposta giusta per il partizionamento verticale, ma non penso che tu possa fare orizzontale con questo. Ad esempio, se ho una colonna 'client_id' su tutti i miei tavoli e voglio tutto con numeri dispari su una casella e tutto con valori pari sull'altra, non penso che i binding funzioneranno. Ho bisogno di sqlalchemy.ext.horizontal_shard.ShardedSession –