2015-04-15 16 views
13

Ich habe einen "Multi-Tenant" Flask Web-Anwendung, die mit 1 "Master" MySQL-Datenbank-Schnittstellen (verwendet, um die Client-Informationen nachschlagen) und Dutzenden von "Client" MySQL-Datenbanken (die alle das gleiche Schema haben).Dynamisch Einstellung Flask-SQLAlchemy Datenbankverbindung in Multi-Tenant-App

Ich versuche derzeit SQLAlchemy zusammen mit der Flask-SQLAlchemy Erweiterung Schnittstelle mit den Datenbanken zu verwenden, aber ich bin zu kämpfen, einen Weg zu finden, den Model ich in meiner App definieren zu ermöglichen dynamisch wechseln Kontext von einer Client-Datenbank zu einem anderen, je nach Client.

Auf den Flask-SQLAlchemy site, ein einfaches Beispiel ist entlang der Linien gezeigt:

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. 

Das einzige Problem ist, die SQLALCHEMY_DATABASE_URI Konfiguration statisch erfolgt. Möglicherweise muss ich zwischen mysql://username:[email protected]/db1 und mysql://username:[email protected]/db1 (oder einem beliebigen anderen MySQL-URI) wechseln, je nachdem, welcher Client die Anfrage stellt.

Ich habe einige ähnliche Fragen (siehe unten) gefunden, aber ich habe noch einen sauberen Weg, um es zu tun, wenn Sie speziell die Erweiterung Flask-SQLAlchemy tun.

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

Flask SQLAlchemy setup dynamic URI

Ich habe auch einige Beispiele gesehen, die für den Umgang mit sharded Datenbanken zur Verfügung gestellt wurden (die auch gelten sollte, da die Datenbanken im Wesentlichen logisch durch Client sharded), aber auch hier nichts Besonderes zu Flask-SQLAlchemy.

Wenn es Sinn macht, Ich bin auch offen für die Verwendung von SQLAlchemy direkt, ohne die Flask-SQLAlchemy-Erweiterung. Ich bin neu in SQLAlchemy - jede Hilfe würde sehr geschätzt werden!

Bearbeiten: Die Tabelle Schemata aus der Datenbank widerspiegeln könnte ein Bonus sein.

+0

Haben Sie http://stackoverflow.com/questions/7923966/flask-sqlalchemy-with-dynamic-database-connections gesehen und falls ja, welche weiteren Fragen haben Sie? –

+2

@SeanVieira Danke - Ich habe diese Antwort nur überprüft und es scheint Sinn zu ergeben.Ich denke daran, eine Anfrage pro Bereich zu machen und sie in 'flask.g' zu speichern. Ich bin meistens verwirrt darüber, wie man die Klasse selbst aufstellt. In dem Beispiel ist "Benutzer" eine Unterklasse von "db.Model" und "db" wird aus der "SQLALCHEMY_DATABASE_URI" initialisiert. Würde es auch funktionieren, wenn 'User' von einer Basisklasse erbt, die mit' sqlalchemy.ext.declarative.declarative_base() '' erstellt wurde, oder gibt es eine andere Klasse, die ich anstelle von Flask-SQLAlchemys 'db.Model' verwenden kann, die nicht davon abhängt auf einer bestimmten Datenbankkonfiguration? – jstol

+0

Lesen Sie diese: http://flask-sqlalchemy.pocoo.org/2.1/binds/ dann überprüfen Sie dies: https://gist.github.com/adhorn/b84dc47175259992d406. – ramabodhi

Antwort

0

Sie könnten so etwas tun. FYI das ist reine SQLAlchemy, nicht mit Flask-SQLAlchemy. Hoffentlich brauchen Sie das für nur-Lese-Sachen. Sie können einige andere Sachen herauszufinden, zu haben Sachen zu schreiben, wie auch die Zuhörer auf Ihrer Sitzung/Modelle

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

Wenn Sie mit Kolben-sqlalchemy 0,12 oder später wird diese Funktion mit Bindet unterstützt.

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

Und Sie können Verbindungsdatenbank in der Modelldefinition angeben.

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

Es wird die mysqldb Auto verwenden. Für weitere Details können Sie das offizielle Dokument beziehen. Multiple Databases with Binds

+0

Dies ist die richtige Antwort für die vertikale Partitionierung, aber ich denke nicht, dass Sie damit horizontal arbeiten können. d. h., wenn ich eine 'client_id'-Spalte in allen meinen Tabellen habe und alles mit ungeraden Zahlen auf einer Box und alles mit geraden Werten auf der anderen möchte, denke ich nicht, dass Bindungen funktionieren. Ich brauche sqlalchemy.ext.horizontal_shard.ShardedSession –