From: Mike Bayer Date: Wed, 16 Jul 2008 21:56:23 +0000 (+0000) Subject: - MapperProperty gets its .key attribute assigned early, in _compile_property. X-Git-Tag: rel_0_5beta3~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5af88c5df1f26d60becc8c60f7d99b3278e7c220;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - MapperProperty gets its .key attribute assigned early, in _compile_property. MapperProperty compilation is detected using a "_compiled" flag. - A mapper which inherits from another, when inheriting the columns of its inherited mapper, will use any reassigned property names specified in that inheriting mapper. Previously, if "Base" had reassigned "base_id" to the name "id", "SubBase(Base)" would still get an attribute called "base_id". This could be worked around by explicitly stating the column in each submapper as well but this is fairly unworkable and also impossible when using declarative [ticket:1111]. --- diff --git a/CHANGES b/CHANGES index 60a1862a43..68171c925f 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,16 @@ CHANGES This is called at the point of attachment for objects via add(), add_all(), delete(), and merge(). + - A mapper which inherits from another, when inheriting + the columns of its inherited mapper, will use any + reassigned property names specified in that inheriting + mapper. Previously, if "Base" had reassigned "base_id" + to the name "id", "SubBase(Base)" would still get + an attribute called "base_id". This could be worked + around by explicitly stating the column in each + submapper as well but this is fairly unworkable + and also impossible when using declarative [ticket:1111]. + - mysql - Quoting of MSEnum values for use in CREATE TABLE is now optional & will be quoted on demand as required. (Quoting was diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index 7d0bae1da7..dc934b9770 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -380,6 +380,7 @@ class MapperProperty(object): """ self.key = key + self._compiled = True self.do_init() def do_init(self): diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 3b45b28ee6..588bc359d3 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -386,7 +386,7 @@ class Mapper(object): l = [(key, prop) for key, prop in self.__props.iteritems()] for key, prop in l: self.__log("initialize prop " + key) - if getattr(prop, 'key', None) is None: + if not getattr(prop, '_compiled', False): prop.init(key, self) self.__log("__initialize_properties() complete") self.compiled = True @@ -674,6 +674,12 @@ class Mapper(object): column_key = (self.column_prefix or '') + column.key + # adjust the "key" used for this column to that + # of the inheriting mapper + for mapper in self.iterate_to_root(): + if column in mapper._columntoproperty: + column_key = mapper._columntoproperty[column].key + self._compile_property(column_key, column, init=False, setparent=True) # do a special check for the "discriminiator" column, as it may only be present @@ -755,13 +761,15 @@ class Mapper(object): self._compile_property(prop.name, ColumnProperty(self.mapped_table.c[key]), init=init, setparent=setparent) self.__props[key] = prop - + prop.key = key + if setparent: prop.set_parent(self) if not self.non_primary: self.class_manager.install_descriptor( key, Mapper._CompileOnAttr(self.class_, key)) + if init: prop.init(key, self) diff --git a/test/orm/inheritance/basic.py b/test/orm/inheritance/basic.py index 6dd49208b9..831d346e63 100644 --- a/test/orm/inheritance/basic.py +++ b/test/orm/inheritance/basic.py @@ -720,6 +720,8 @@ class OverrideColKeyTest(ORMTest): mapper(Base, base) mapper(Sub, subtable, inherits=Base) + # Sub gets a "base_id" property using the "base_id" + # column of both tables. self.assertEquals( class_mapper(Sub).get_property('base_id').columns, [base.c.base_id, subtable.c.base_id] @@ -727,7 +729,8 @@ class OverrideColKeyTest(ORMTest): def test_override_explicit(self): # this pattern is what you see when using declarative - # in particular + # in particular, here we do a "manual" version of + # what we'd like the mapper to do. class Base(object): pass @@ -738,7 +741,8 @@ class OverrideColKeyTest(ORMTest): 'id':base.c.base_id }) mapper(Sub, subtable, inherits=Base, properties={ - # this is required...good luck getting any end users to figure this out + # this is the manual way to do it, is not really + # possible in declarative 'id':[base.c.base_id, subtable.c.base_id] }) @@ -792,11 +796,10 @@ class OverrideColKeyTest(ORMTest): # PK col assert s2.id == s2.base_id != 15 - @testing.fails_on_everything_except() def test_override_implicit(self): - # this is how the pattern looks intuitively, - # including the intuition of the SQLAlchemy creator, - # but unfortunately....zzzt + # this is how the pattern looks intuitively when + # using declarative. + # fixed as part of [ticket:1111] class Base(object): pass @@ -810,17 +813,16 @@ class OverrideColKeyTest(ORMTest): 'id':subtable.c.base_id }) - # what in fact happens is that "Sub" gets the column "base_id" mapped - # as well. what *should* happen is, Sub mapper should reconcile - # the inherited "id" from Base. right now Base's "id" is ignored - # totally because the same key is present in Sub. + # Sub mapper compilation needs to detect that "base.c.base_id" + # is renamed in the inherited mapper as "id", even though + # it has its own "id" property. Sub's "id" property + # gets joined normally with the extra column. self.assertEquals( class_mapper(Sub).get_property('id').columns, [base.c.base_id, subtable.c.base_id] ) - # this fails too s1 = Sub() s1.id = 10 sess = create_session()