2017-05-06 53 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

相关问题