2017-05-06 3 views
0

Wir haben mehrere Kunden in einem ERP-System. Jeder Client hat eine eigene Datenbank. Die Datenbanken sind hinsichtlich des Schemas identisch.Dynamisch erstellen sqlAlchemy Metaclass basierend auf Tabelle Bibliothek

Fragen Sie mich nicht, warum, aber die ERP-Datenbank hat keine formell definierten PKs, und so ist es nicht möglich, die Datenbank widerzuspiegeln ... Stattdessen haben wir festgestellt, dass eine Metaklasse, mit einer Tabelle Deklaration PK detailliert , und Autoload funktioniert. Ein Beispiel:

class Customers(Base): 

    __table__ = Table('Customers', Base.metadata, 
         Column('UniqueNo', Integer, primary_key=True), 
         schema = 'databaseName.schema', 
         autoload = True 

Ein schnelles nicht auf dem schema = Teil. Das Schema ist für jede Datenbank gleich, aber die Benennung des Schemas (wie auch der Name der Datenbank selbst) ist unterschiedlich. Das Definieren des Schemas in der Metaklasse ermöglicht es uns, über die Datenbanken hinweg

anzufragen. Beim Erstellen der Codestruktur ist die Metaclass-Deklaration am einfachsten manuell durchzuführen. Eine .py-Datei für jede Datenbank haben und dieselbe Metaklassendeklaration in jeder Datei ausführen, nur das Schema ändern und dem Klassennamen ein Suffix hinzufügen, um Verwechslungen zu vermeiden. Wie so:

client1.py

class Customers_1(Base): 

    __table__ = Table('Customers', Base.metadata, 
         Column('UniqueNo', Integer, primary_key=True), 
         schema = 'Dbclient1.client1Schema', 
         autoload = True 

client2.py

class Customers_2(Base): 

    __table__ = Table('Customers', Base.metadata, 
         Column('UniqueNo', Integer, primary_key=True), 
         schema = 'Dbclient2.client2Schema', 
         autoload = True 

es zu tun auf diese Weise funktioniert, aber unsere Hoffnung ist, dass wir die Menge an Code reduzieren könnte durch dynamische Erstellung der Metaklassen basierend auf nur einer Datei ERPTables.py. Beispiel:

ERPTables.py 

class Customers(Base): 

    __table__ = Table('Customers', Base.metadata, 
         Column('UniqueNo', Integer, primary_key=True), 
         autoload = True 

Dies führt uns die Straße der Metaklassen, die unbekanntes Gebiet ist. Ich habe den Punkt erreicht, an dem ich die Deklaration der Metaklasse dynamisch erstellen kann. Aber: Die Registrierung der Erklärung ist, wo mein Verständnis zu kurz kommt. Ich habe so weit gekommen:

from sqlalchemy import Table 
import ERPTables 
import inspect 

def iterate_ERPTables_Tables(): 
    for table in inspect.getmembers(ERPTables): 
     if isinstance(table[1], Table) : 
      return table[0], table[1] 


dbSchemas = {'_1': 'Dbclient1.client1Schema', '_2': 'Dbclient2.client2Schema'} 

tables = [iterate_TableTest_Tables()] 

for key in dbSchemas: 

    for table in tables: 

      cls = type(table[0] + key, (Base,), {'__tablename__': table[0], '__table__': table[1]})   

      break 

Dieser Code funktioniert! Das einzige Problem ist, dass die SA-Metaklasse Cls genannt wird. Daher die break. Ohne es zu versuchen, deklarieren wir mehrere Metaklassen mit demselben Klassennamen.

Ich habe verschiedene Ansätze versucht, dieses Problem zu beheben, wie Versuche, die nicht vertraut metaclass Perspektive zu verwenden:

dbSchemas = {'_1': 'Dbclient1.client1Schema', '_2': 'Dbclient2.client2Schema'} 

tables = [iterate_TableTest_Tables()] 

for key in dbSchemas: 

    for table in tables: 

      type(table[0] + key, (Base,), {'__tablename__': table[0], '__table__': table[1]}).__new__   

Um eine volle geblasen Hack Workarounds:

dbSchemas = {'_1': 'Dbclient1.client1Schema', '_2': 'Dbclient2.client2Schema'} 

tables = [iterate_TableTest_Tables()] 

for key in dbSchemas: 

    for table in tables: 

      exec("%s = %s" % (table[0] + key, type(table[0] + key, (Base,), {'__tablename__': table[0], '__table__': table[1]}))) 

Aber alle meine attemtps gewesen Ohne Erfolg und so, am Ende des Seils, wende ich mich an SO in der Hoffnung, dass mir jemand zeigen kann, wie ich das lösen kann!

PS: Falls jemand sich fragt, habe ich noch nicht gelöst, wie man das Schema aus dem dbSchemas Dictionary in die Metaclass injiziert. Ich hoffe, einen Weg zu finden, aber ein Problem nach dem anderen!

Antwort

1

Wenn Sie den Verweis auf die Klassen exportieren möchten, können Sie sie zu globals() hinzufügen:

globals()[table[0] + key] = type(...) 
+0

Heilige f ... Das hat funktioniert. Danke! @univerio – Rookie

+0

Vielen Dank dafür! Es war eine interessante Antwort, ich war auf dem Weg, das Problem in diesen Raum zu reduzieren. Ich schrieb [eine andere Frage] (http: // stackoverflow.com/questions/43823552/difference-zwischen-deklarieren-eine-Klasse-mit-Klasse-vs-Typ), als ein allgemeineres Problem/Beobachtung styled. Es wäre toll, wenn Sie das beantworten könnten. Sowohl für meine, als auch für andere Leser willen. An dieser Frage scheint es Interesse zu geben. Danke nochmal für deine Hilfe! – Rookie

Verwandte Themen