早在2010年10月,我就發佈了this question到Sqlalchemy用戶列表。 當時,我只是使用了郵件中提到的clear_mappers
解決方法,並沒有試圖找出問題所在。那對我來說很調皮。今天我再次遇到了這個bug,並決定構建一個最小的例子,如下所示。邁克爾在2006年還提到了probably the same issue。我決定在這裏跟進,讓邁克爾從我愚蠢的問題中解脫出來。「Class has a primary mapper defined」error with SQLAlchemy
因此,結果似乎是給定的類定義,你不能有多個定義的映射器。在我的情況下,我有在模塊範圍內聲明的Pheno
類(我假設這是頂級範圍),每次運行make_tables
時,它都會嘗試定義另一個映射器。
Mike寫道:「基於上述問題的描述,您需要確保您的Python類與映射器的聲明範圍相同。您收到的錯誤消息表明'Pheno'聲明在模塊中水平。」這會照顧到這個問題,但我如何管理這個問題,而不改變我目前的結構?我有什麼其他選擇,如果有的話?很明顯,mapper沒有像「如果mapper已經被定義,退出而沒有做任何事情」的選項,這將很好地照顧它。我想我可以定義一個包裝函數,但那會非常難看。
from sqlalchemy import *
from sqlalchemy.orm import *
def make_pheno_table(meta, schema, name='pheno'):
pheno_table = Table(
name, meta,
Column('patientid', String(60), primary_key=True),
schema=schema,
)
return pheno_table
class Pheno(object):
def __init__(self, patientid):
self.patientid = patientid
def make_tables(schema):
from sqlalchemy import MetaData
meta = MetaData()
pheno_table = make_pheno_table(meta, schema)
mapper(Pheno, pheno_table)
table_dict = {'metadata': meta, 'pheno_table':pheno_table}
return table_dict
table_dict = make_tables('foo')
table_dict = make_tables('bar')
錯誤消息如下。使用SQLAlchemy 0.6.3-3進行Debian壓縮測試。
$ python test.py
Traceback (most recent call last):
File "test.py", line 25, in <module>
table_dict = make_tables('bar')
File "test.py", line 20, in make_tables
mapper(Pheno, pheno_table)
File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/__init__.py", line 818, in mapper
return Mapper(class_, local_table, *args, **params)
File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/mapper.py", line 209, in __init__
self._configure_class_instrumentation()
File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/mapper.py", line 381, in _configure_class_instrumentation
self.class_)
sqlalchemy.exc.ArgumentError: Class '<class '__main__.Pheno'>' already has a primary mapper defined. Use non_primary=True to create a non primary Mapper. clear_mappers() will remove *all* current mappers from all classes.
編輯:每在SQLAlchemy: The mapper() API的文檔,我上面
from sqlalchemy.orm.exc import UnmappedClassError
try:
class_mapper(Pheno)
except UnmappedClassError:
mapper(Pheno, pheno_table)
如果映射器沒有爲苯氧定義,它拋出一個UnmappedClassError
更換mapper(Pheno, pheno_table)
。這至少不會在我的測試腳本中返回一個錯誤,但我沒有檢查它是否真正起作用。註釋?
EDIT2:每丹尼斯的建議,以下工作:
class Tables(object):
def make_tables(self, schema):
class Pheno(object):
def __init__(self, patientid):
self.patientid = patientid
from sqlalchemy import MetaData
from sqlalchemy.orm.exc import UnmappedClassError
meta = MetaData()
pheno_table = make_pheno_table(meta, schema)
mapper(Pheno, pheno_table)
table_dict = {'metadata': meta, 'pheno_table':pheno_table, 'Pheno':Pheno}
return table_dict
table_dict = Tables().make_tables('foo')
table_dict = Tables().make_tables('bar')
然而,表面上類似於
# does not work
class Tables(object):
class Pheno(object):
def __init__(self, patientid):
self.patientid = patientid
def make_tables(self, schema):
from sqlalchemy import MetaData
from sqlalchemy.orm.exc import UnmappedClassError
meta = MetaData()
pheno_table = make_pheno_table(meta, schema)
mapper(self.Pheno, pheno_table)
table_dict = {'metadata': meta, 'pheno_table':pheno_table, 'Pheno':self.Pheno}
return table_dict
table_dict = Tables().make_tables('foo')
table_dict = Tables().make_tables('bar')
沒有。我收到了和以前一樣的錯誤信息。 我不太瞭解範圍問題,足以說明原因。 是不是Pheno
類在兩種情況下在某種局部範圍?
謝謝你的明確解釋。你能否建議如何「定義單獨的類映射到第二個表」,而不改變我的代碼的結構? – 2011-05-19 10:01:01
謝謝。我不知道有可能在函數內定義一個類。我花了一些時間試圖找到這個昨天的文件,沒有成功。你能提供一個參考嗎?實際上,我的代碼中'make_tables'的實際版本是在一個類 - 類的Tables(object):... def make_tables(schema)...'中。在那裏定義類是否有意義? – 2011-05-19 11:23:27