2017-05-06 117 views
0

我們在ERP系統中有幾個客戶端。每個客戶端都有自己的數據庫。數據庫在架構方面是相同的。基於表庫動態創建sqlAlchemy Metaclass

不要問我爲什麼,但ERP數據庫沒有正式定義的PK,所以它不可能反映數據庫......反而我們發現聲明一個Metaclass和一個表聲明,詳述了PK和自動加載工程。舉個例子:

class Customers(Base): 

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

快速不上schema =一部分。每個數據庫的模式都是相同的,但模式的命名(以及數據庫名稱本身)是不同的。定義在元類的模式就是這樣,使我們能夠翻過查詢數據庫,能夠

當創建的代碼結構,要做到元類聲明的最簡單的方法是手動。每個數據庫都有一個.py文件,並在每個文件中執行相同的Metaclass聲明,僅更改模式,並向類名添加後綴以避免命名混淆。像這樣:

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 

這樣做,這樣的工作,但我們的希望是,我們可以通過動態創建減少代碼量的元類僅基於一個ERPTables.py文件。例如:

ERPTables.py 

class Customers(Base): 

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

這使我們走上了Metaclasses這條陌生的領域。我已經到了能夠動態創建元類聲明的地步。但是:註冊聲明是我理解不足的地方。我來了這麼遠:

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 

此代碼有效!唯一的問題是SA Metaclass命名爲cls。因此break。沒有它,我們試圖聲明幾個具有相同類名的元類。

我嘗試了好幾種方法來解決這個問題,喜歡嘗試使用不熟悉的元類觀點:

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__   

要完全成熟的破解工作變通:

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]}))) 

但是我所有的attemtps的已沒有絲毫的意義,所以,在繩索的末端,我轉向了SO,希望有人能告訴我如何解決這個問題! PS:如果有人想知道,我還沒有解決如何將模式從dbSchemas注入到Metaclass中。我希望找到一種方法,但一次只能解決一個問題!

回答

1

如果你要導出的參考類,你可以將它們添加到globals()

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

聖F的這一工作。謝謝! @univerio – Rookie

+0

謝謝你!這是一個有趣的答案,我正在努力將問題減少到這個空間。我寫了[另一個問題](http:// stackoverflow。com/questions/43823552 /聲明類 - 與類 - 類型之間的區別),作爲一個更普遍的問題/觀察。如果你能回答這個問題,那將是非常好的。既爲我,也爲其他讀者着想。看起來這個問題有興趣。再次感謝你的幫助! – Rookie