Hello,
I experience some strange behaviour from polymorphic mappers. It seems
that convert_result_value doesn't get called for all columns of
polymorphic mappers.
Here's a modified polymorhpic example from sqlalchemy distribution
(also in an attach):
===================================================================
# -*- coding: cp1251 -*-
from sqlalchemy import *
import datetime
class SqlStrMixing( object ):
def __str__( self ):
s = [ self.__class__.__name__ + ': ' ]
for c in self.c:
s.append( u'%s=%s ' % ( c.key, getattr(self, c.key) ) )
result = ''.join(s).encode( 'cp866' )
return result
# Sqlite and postgres (psycopg2) give different results
engine_uri = 'sqlite:///'
#engine_uri = 'postgres://billing:[EMAIL PROTECTED]:5432/billing'
metadata = BoundMetaData(engine_uri,
convert_unicode=True)
people = Table('people', metadata,
Column('person_id', Integer, primary_key=True),
Column('name', String(50)),
Column('date', DateTime ),
Column('type', String(30)))
engineers = Table('engineers', metadata,
Column('person_id', Integer, ForeignKey('people.person_id'),
primary_key=True),
Column('engineer_info', String(50)),
)
managers = Table('managers', metadata,
Column('person_id', Integer, ForeignKey('people.person_id'),
primary_key=True),
Column('manager_data', String(50)),
)
addresses = Table( 'addresses', metadata,
Column('address_id', Integer, primary_key=True),
Column('person_id', Integer, ForeignKey('people.person_id') ),
Column('address', String(150)),
)
metadata.drop_all()
metadata.create_all()
person_join = polymorphic_union(
{
'engineer': people.join(engineers),
'manager': people.join(managers),
'person': people.select(people.c.type=='person'),
}, None, 'pjoin')
class Person(SqlStrMixing):
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
self.date = datetime.datetime.today()
def __repr__(self):
return self.__class__.__name__ + " " + self.name
class Manager(Person):
def __repr__(self):
return self.__class__.__name__ + " " + self.name + " " +
self.manager_data
class Engineer(Person):
def __repr__(self):
return self.__class__.__name__ + " " + self.name + " " +
self.engineer_info
class Address(SqlStrMixing):
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
mapper( Address, addresses )
person_mapper = mapper(Person, people, select_table=person_join, \
polymorphic_on=person_join.c.type, polymorphic_identity='person',
properties= \
{
'addresses' : relation( Address, backref='person' )
})
mapper( Engineer, engineers, inherits=person_mapper, \
polymorphic_identity='engineer' )
mapper( Manager, managers, inherits=person_mapper, \
polymorphic_identity='manager' )
session = create_session(echo_uow=False)
p1 = Engineer( name=u'John', engineer_info=u'some info' )
p2 = Manager( name=u'Jack', manager_data=u'some_data' )
session.save(p1)
session.save(p2)
session.flush()
session.close()
session = create_session(echo_uow=False)
person_list = session.query(Person).select()
for p in person_list:
print type(p.name)
print p.name
try:
print type(p.engineer_info)
print p.engineer_info
except:
pass
try:
print type(p.manager_data)
print p.manager_data
except:
pass
metadata.drop_all()
============================================================
I modifiled my version of sqlalchemy to print some info whent
types.String.convert_result_value or
types.Unicode.convert_result_value are called.
Output of this script when postgres is used:
========================================
types.String.convert_result_value
value: engineer
types.String.convert_result_value
value: John
types.String.convert_result_value
value: engineer
types.String.convert_result_value
value: some info
types.String.convert_result_value
value: manager
types.String.convert_result_value
value: Jack
types.String.convert_result_value
value: manager
<type 'unicode'>
John
<type 'unicode'>
some info
<type 'unicode'>
Jack
<type 'str'>
some_data
It seems that for Manager.manager_data convert_result_value is not
called at all and it's data left as is. I.e. as a string, when it
should be unicode. Perhap's that's fine for people whith ASCII
encoding but for people using UTF8 and national encodings it's a total
disaster.
When using sqlite:
========================================
types.String.convert_result_value
value: manager
types.String.convert_result_value
value: Jack
types.String.convert_result_value
value: manager
types.String.convert_result_value
value: engineer
types.String.convert_result_value
value: John
types.String.convert_result_value
value: engineer
types.String.convert_result_value
value: some info
<type 'unicode'>
Jack
<type 'unicode'>
some_data
<type 'unicode'>
John
<type 'unicode'>
some info
convert_result_value again is not called for Manager.manager_data but
value is unicode because of sqlite option to convert string to unicode
usint UTF8 for database encoding.
Am I doing something wrong, or is it a bug in sqlalchemy?
I tried to track this bug myself but there's so many magic in
sqlalchemy, so I couldn't find the bug... :-(
--
Best regards,
Vasily mailto:[EMAIL PROTECTED]
# -*- coding: cp1251 -*-
from sqlalchemy import *
import datetime
class SqlStrMixing( object ):
def __str__( self ):
s = [ self.__class__.__name__ + ': ' ]
for c in self.c:
s.append( u'%s=%s ' % ( c.key, getattr(self, c.key) ) )
result = ''.join(s).encode( 'cp866' )
return result
engine_uri = 'sqlite:///'
#engine_uri = 'postgres://billing:[EMAIL PROTECTED]:5432/billing'
metadata = BoundMetaData(engine_uri,
convert_unicode=True)
people = Table('people', metadata,
Column('person_id', Integer, primary_key=True),
Column('name', String(50)),
Column('date', DateTime ),
Column('type', String(30)))
engineers = Table('engineers', metadata,
Column('person_id', Integer, ForeignKey('people.person_id'),
primary_key=True),
Column('engineer_info', String(50)),
)
managers = Table('managers', metadata,
Column('person_id', Integer, ForeignKey('people.person_id'),
primary_key=True),
Column('manager_data', String(50)),
)
addresses = Table( 'addresses', metadata,
Column('address_id', Integer, primary_key=True),
Column('person_id', Integer, ForeignKey('people.person_id') ),
Column('address', String(150)),
)
metadata.drop_all()
metadata.create_all()
person_join = polymorphic_union(
{
'engineer': people.join(engineers),
'manager': people.join(managers),
'person': people.select(people.c.type=='person'),
}, None, 'pjoin')
class Person(SqlStrMixing):
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
self.date = datetime.datetime.today()
def __repr__(self):
return self.__class__.__name__ + " " + self.name
class Manager(Person):
def __repr__(self):
return self.__class__.__name__ + " " + self.name + " " +
self.manager_data
class Engineer(Person):
def __repr__(self):
return self.__class__.__name__ + " " + self.name + " " +
self.engineer_info
class Address(SqlStrMixing):
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
mapper( Address, addresses )
person_mapper = mapper(Person, people, select_table=person_join, \
polymorphic_on=person_join.c.type, polymorphic_identity='person',
properties= \
{
'addresses' : relation( Address, backref='person' )
})
mapper( Engineer, engineers, inherits=person_mapper, \
polymorphic_identity='engineer' )
mapper( Manager, managers, inherits=person_mapper, \
polymorphic_identity='manager' )
session = create_session(echo_uow=False)
p1 = Engineer( name=u'John', engineer_info=u'some info' )
p2 = Manager( name=u'Jack', manager_data=u'some_data' )
session.save(p1)
session.save(p2)
session.flush()
session.close()
session = create_session(echo_uow=False)
person_list = session.query(Person).select()
for p in person_list:
print type(p.name)
print p.name
try:
print type(p.engineer_info)
print p.engineer_info
except:
pass
try:
print type(p.manager_data)
print p.manager_data
except:
pass
metadata.drop_all()
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Sqlalchemy-users mailing list
Sqlalchemy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users