В октябре 2010 года я разместил этот вопрос в списке пользователей Sqlalchemy.
В то время я просто использовал обходной путь clear_mappers
, упомянутый в сообщении, и не пытался выяснить, в чем проблема. Это было очень непослушно с моей стороны. Сегодня я снова столкнулся с этой ошибкой и решил создать минимальный пример, который показан ниже. Майкл также обратился к тому, что , вероятно, та же проблема , еще в 2006 году. Я решил продолжить здесь, чтобы дать Майклу отдохнуть от моих глупых вопросов.
Таким образом, в результате получается, что для данного определения класса не может быть определено более одного сопоставителя. В моем случае у меня есть класс Pheno
, объявленный в области видимости модуля (я предполагаю, что здесь это область верхнего уровня), и каждый раз, когда make_tables
выполняется, он пытается определить другой преобразователь.
Майк писал: «Исходя из описания проблемы, приведенной выше, вы должны убедиться, что ваши классы Python объявлены в той же области, что и ваши преобразователи. Получаемое сообщение об ошибке предполагает, что« Pheno »объявлен на уровне модуля». «. Это решило бы проблему, но как мне справиться с этим, не меняя мою нынешнюю структуру? Какие еще есть варианты, если они есть? Очевидно, у 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: API mapper () , я мог бы заменить mapper(Pheno, pheno_table)
выше на
from sqlalchemy.orm.exc import UnmappedClassError
try:
class_mapper(Pheno)
except UnmappedClassError:
mapper(Pheno, pheno_table)
Если картограф не определен для Pheno, он выдает UnmappedClassError
. По крайней мере, это не возвращает ошибку в моем тестовом скрипте, но я не проверял, работает ли он на самом деле. Комментарии?
РЕДАКТИРОВАТЬ2: По предложению Дениса, следующие работы:
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
в обоих случаях не входит в какую-то локальную область видимости?