2010-05-04 12 views
19

Wir müssen SQLAlchemy-Klassen erstellen, um auf mehrere externe Datenquellen zuzugreifen, deren Anzahl im Laufe der Zeit zunimmt. Wir verwenden die deklarative Basis für unsere ORM-Kernmodelle und ich weiß, dass wir neue ORM-Klassen manuell mit autoload = True angeben können, um das Mapping automatisch zu generieren.Dynamische Klassenerstellung in SQLAlchemy

Das Problem ist, dass wir brauchen, um sie dynamisch, so etwas zu können, erzeugen unter:

from sqlalchemy.ext.declarative import declarative_base 
Base = declarative_base() 

stored={} 
stored['tablename']='my_internal_table_name' 
stored['objectname']='MyObject' 

und in so etwas wie dieses dynamisch drehen:

class MyObject(Base): 
    __tablename__ = 'my_internal_table_name' 
    __table_args__ = {'autoload':True} 

Wir wollen nicht die Klassen, die länger als nötig bestehen bleiben, um eine Verbindung zu öffnen, die Abfragen auszuführen und dann die Verbindung zu schließen. Daher können wir idealerweise die Elemente in die "gespeicherte" Variable oben in eine Datenbank einfügen und sie nach Bedarf ziehen. Die andere Herausforderung besteht darin, dass der Objektname (z. B. "MyObject") auf verschiedenen Verbindungen verwendet werden kann, so dass wir ihn nicht einmal definieren und herum behalten können.

Alle Vorschläge, wie dies erreicht werden könnte, würden sehr geschätzt werden.

Dank ...

Antwort

24

Sie dynamisch MyObject mit der 3-argument call to type erstellen:

type(name, bases, dict) 

    Return a new type object. This is essentially a dynamic form of the 
    class statement... 

Zum Beispiel:

mydict={'__tablename__':stored['tablename'], 
     '__table_args__':{'autoload':True},} 

MyObj=type(stored['objectname'],(Base,),mydict) 
print(MyObj) 
# <class '__main__.MyObject'> 
print(MyObj.__base__) 
# <class '__main__.Base'> 
print(MyObj.__tablename__) 
# my_internal_table_name 
print(MyObj.__table_args__) 
# {'autoload': True} 
+0

Junge ... ich dumm fühlen. Solch eine einfache Lösung. Ich wusste nicht, dass die Typ-Methode so mächtig war. Ich änderte die Lösung leicht, um den Objektnamen in den globalen Raum einzufügen, damit er direkt in SQLAlchemy-Abfragen eingefügt werden konnte: globals() [gespeichert ['Objektname']] = Typ (gespeichert ['Objektname'], (Base,), mydict) Danke ... tolle Lösung. – PlaidFan

+3

Fühlen Sie sich nicht dumm! Ich habe diesen Trick gelernt, indem ich beobachtet habe, wie andere ihn hier auf SO benutzen. Jetzt kennen Sie den Trick und können Ihre Freunde begeistern. :) – unutbu