Таблица картирования SQLALCHEMY с столбцами не ASCII для класса
-
27-10-2019 - |
Вопрос
item = Table('Item', metadata, autoload=True, autoload_with=engine, encoding = 'cp1257')
class Item(object):
pass
from sqlalchemy.orm import mapper
mapper(Item, item)
Я получаю ошибку:
line 43, in <module>
mapper(Item, item)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\__init__.py", line 890, in mapper
return Mapper(class_, local_table, *args, **params)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 211, in __init__
self._configure_properties()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 578, in _configure_properties
setparent=True)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 618, in _configure_property
self._log("_configure_property(%s, %s)", key, prop.__class__.__name__)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 877, in _log
(self.non_primary and "|non-primary" or "") + ") " +
File "C:\Python27\lib\site-packages\sqlalchemy\util.py", line 1510, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "C:\Python27\lib\site-packages\sqlalchemy\sql\expression.py", line 3544, in description
return self.name.encode('ascii', 'backslashreplace')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xeb in position 7: ordinal not in range(128)
Я подключаюсь к MSSQL. Автоогрузка таблицы, кажется, работает. Я получаю только эту ошибку, пытаясь карту. Спасибо всем за помощь!
Решение
Сопоставление таблицы с классом создает сопоставленные свойства на классе. Свойства имеют одинаковое имя столбцов по умолчанию. Поскольку Python 2.x допускает только идентификаторы ASCII, это не удается, если у вас есть имена столбцов, не являющихся ASCII.
Единственное решение, о котором я могу придумать, - это дать идентификаторам другое имя при сопоставлении таблицы в класс.
Пример ниже делает это. Обратите внимание, что я создаю таблицу в коде для простоты, чтобы любой мог запустить код без существующей таблицы. Но вы можете сделать то же самое с отраженной таблицей.
#-*- coding:utf-8 -*-
import sqlalchemy as sa
import sqlalchemy.orm
engine = sa.create_engine('sqlite://', echo=True) # new memory-only database
metadata = sa.MetaData(bind=engine)
# create a table. This could be reflected from the database instead:
tb = sa.Table('foo', metadata,
sa.Column(u'id', sa.Integer, primary_key=True),
sa.Column(u'nomé', sa.Unicode(100)),
sa.Column(u'ãéìöû', sa.Unicode(100))
)
tb.create()
class Foo(object):
pass
# maps the table to the class, defining different property names
# for some columns:
sa.orm.mapper(Foo, tb, properties={
'nome': tb.c[u'nomé'],
'aeiou': tb.c[u'ãéìöû']
})
После этого вы можете использовать Foo.nome
Чтобы ссылаться на nomé
колонка и Foo.aeiou
Чтобы ссылаться на ãéìöû
столбец.
Другие советы
Я столкнулся с той же проблемой и, наконец, сумел сделать это заменить таблицу ['' Column ']. Ключ после автозагрузки, просто сделайте все ваши таблицы унаследовать этот, а затем изменить замену имени столбца в методе MAPTO или переопределить вручную по желаемым именам с помощью желаемых имен Словарь и метод Columns_descriptor. Я не знаю, является ли это не правильным способом сделать это, но после того, как поиск часами - лучший аромат, который у меня есть.
class SageProxy(object):
@classmethod
def ismapped(cls, table_name=None):
if mappings:
if table_name:
if mappings.has_key(table_name):
tmap=mappings[table_name]
if tmap.has_key('class'):
tclass=tmap['class']
if tclass is cls:
return True
else:
for m in mappings:
if cls is m['class']:
return True
return False
@classmethod
def mappingprops(cls):
#override this to pass properties to sqlalchemy mapper function
return None
@classmethod
def columns_descriptors(cls):
#override this to map columns to different class properties names
#return dictionary where key is the column name and value is the desired property name
return {}
@classmethod
def mapTo(cls, table_name, map_opts=None):
if not cls.ismapped(table_name):
tab_obj=Table(table_name,sage_md,autoload=True)
for c in tab_obj.c:
#clean field names
tab_obj.c[c.name].key=c.key.replace(u'%',u'Porcentaje').replace(u'ñ',u'ny').replace(u'Ñ',u'NY').replace(u'-',u'_')
for k,v in cls.columns_descriptors():
if tab_obj.c[k]:
tab_obj.c[k].key=v
mapper(cls, tab_obj, properties=cls.mappingprops())
mappings[table_name]={'table':tab_obj,'class':cls}
return cls
Я ожидаю, что это будет полезно
Я обнаружил, что мог бы сделать это с простым дополнением к моему отраженному классу:
metadata = MetaData(bind=engine, reflect=True)
sm = sessionmaker(bind=engine)
class tblOrders(Base):
__table__ = metadata.tables['tblOrders']
meter = __table__.c['Meter#']
meter
теперь намечен на основной Meter#
столбец, который позволяет этому коду работать:
currOrder = tblOrders()
currOrder.meter = '5'
Без отображения Python видит это как сломанное утверждение, потому что Meter
За последующим комментарием не существует в объекте.