Pregunta

item = Table('Item', metadata, autoload=True, autoload_with=engine, encoding = 'cp1257')

class Item(object):
    pass

from sqlalchemy.orm import mapper
mapper(Item, item)

Recibo error:

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)

Me estoy conectando a MSSQL. Table Autoload parece funcionar. Solo recibo este error al intentar mapear. ¡Gracias a todos por la ayuda!

¿Fue útil?

Solución

Mapear la tabla a una clase crea propiedades asignadas en la clase. Las propiedades tienen el mismo nombre de las columnas, de forma predeterminada. Dado que Python 2.x solo permite identificadores ASCII, eso falla si tiene nombres de columnas no ASCII.

La única solución que se me ocurre es dar a los identificadores un nombre diferente al asignar la tabla a una clase.

El ejemplo a continuación hace eso. Tenga en cuenta que estoy creando la tabla en el código por simplicidad, por lo que cualquiera puede ejecutar el código sin tener la tabla existente. Pero podrías hacer lo mismo con una tabla reflejada.

#-*- 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'ãéìöû']
})

Después de eso puedes usar Foo.nome para referirse al nomé columna y Foo.aeiou para referirse al ãéìöû columna.

Otros consejos

Me enfrenté al mismo problema y finalmente logré hacerlo reemplazando la tabla ['columna']. Clave después de que se acelere, solo haga que todas las clases de su tabla hereden esta y luego modifique el reemplazo del nombre de la columna en el método Mapto o anule manualmente los nombres deseados con Un método de diccionario y columna_descriptor. No sé si esta no es la forma correcta de hacerlo, pero después de buscar horas es el mejor abril que tengo.

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

Espero que sea útil

Descubrí que podía hacer esto con una simple adición a mi clase reflejada:

metadata = MetaData(bind=engine, reflect=True)
sm = sessionmaker(bind=engine)

class tblOrders(Base):
    __table__ = metadata.tables['tblOrders']
    meter = __table__.c['Meter#']

meter ahora está asignado al subyacente Meter# columna, que permite que este código funcione:

currOrder = tblOrders()
currOrder.meter = '5'

Sin el mapeo, Python lo ve como una declaración rota porque Meter seguido de un comentario no existe en el objeto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top