我正在使用声明性基础创建一个带有 SQLAlchemy 的后端应用程序。ORM 需要大约 15 个表,每个表映射到 SQLAlchemy 中的一个类对象。因为这些类对象的定义都是一样的,所以我认为工厂模式可以更简洁地生成类。但是,这些类不仅需要定义,还必须分配给唯一的变量名,以便可以通过项目导入和使用。
(对不起,如果这个问题有点长,我更新了它,因为我更好地理解了这个问题。)
因为我们有这么多列(~1000),所以我们在外部文本文件中定义它们的名称和类型以保持可读性。完成了声明模型的一种方法是这样的:
class Foo1(Base):
__tablename___ = 'foo1'
class Foo2(Base):
__tablename___ = 'foo2'
... etc
然后我可以通过循环外部文本文件的内容并setattr()
在每个类定义上使用来添加列。
这没关系,但感觉太重复了,因为我们有大约 15 张桌子。因此,我尝试编写一个可以动态定义类的工厂函数。
def orm_factory(class_name):
class NewClass(Base):
__tablename__ = class_name.lower()
NewClass.__name__ = class_name.upper()
return NewClass
同样,我可以遍历列并使用setattr()
. 当我把它放在一起时,它看起来像这样:
for class_name in class_name_list:
ORMClass = orm_factory(class_name)
header_keyword_list = get_header_keyword_list(class_name)
define_columns(ORMClass, header_keyword_list)
Whereget_header_keyword_list
获取列信息并define_columns
执行setattr()
分配。当我使用它并运行Base.metadata.create_all()
SQL 模式时,生成就好了。
但是,当我尝试将这些类定义导入另一个模型时,我收到如下错误:
SAWarning: The classname 'NewClass' is already in the registry of this declarative base, mapped to <class 'ql_database_interface.IR_FLT_0'>
根据我昨天学到的知识,我现在意识到这完全有意义:Python 类变量名与 __name__。
您可以通过type
在工厂函数中用作类生成器来解决此问题(正如以下两个答案所做的那样)。但是,这并不能解决能够导入类的问题,因为虽然类是在工厂函数中动态构造的,但该函数的输出分配给的变量是静态的。即使它是动态的,例如字典键,它也必须在模块名称空间中才能从另一个模块导入。有关更多详细信息,请参阅我的答案。