我正在使用聲明性基礎使用SQLAlchemy創建後端應用程序。 ORM需要大約15個表,每個表映射到SQLAlchemy中的類對象。因爲這些類對象都是完全相同的,所以我認爲工廠模式可以更簡潔地生成類。但是,這些類不僅必須定義,而且必須分配給唯一的變量名稱,以便可以通過項目導入和使用它們。SQLAlchemy中的動態Python類定義
(很抱歉,如果這個問題是有點長,我更新了它,因爲我更好地理解這個問題。)
因爲我們有這麼多列(〜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)
凡get_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 class variable name vs __name__。
您可以在工廠函數中使用type
作爲類生成器來解決此問題(以下是兩個答案)。但是,這並不能解決導入類的問題,因爲雖然類在工廠函數中動態構建,但該函數的輸出分配給的變量是靜態的。即使它是動態的,如字典鍵,它也必須位於模塊名稱空間中才能從其他模塊導入。查看我的答案瞭解更多詳情。
爲什麼你需要,如果你添加的構造類的外範圍容器(list_of_classes.append或字典)修改全局?容器本身可以跨模塊導入,因爲容器將在模塊範圍內。 – cowbert