From: Mike Bayer Date: Wed, 2 Feb 2011 23:10:07 +0000 (-0500) Subject: - Fixed bug where "middle" class in a polymorphic hierarchy X-Git-Tag: rel_0_7b1~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c5b4938a9a2918a14397cff3edcee8c69ca249ea;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Fixed bug where "middle" class in a polymorphic hierarchy would have no 'polymorphic_on' column if it didn't also specify a 'polymorphic_identity', leading to strange errors upon refresh, wrong class loaded when querying from that target. [ticket:2038] --- diff --git a/CHANGES b/CHANGES index 7ab5fbd023..7eca04fa82 100644 --- a/CHANGES +++ b/CHANGES @@ -191,6 +191,12 @@ CHANGES has no primary keys on the locally mapped table (but has pks on the superclass table). [ticket:2019] + - Fixed bug where "middle" class in a polymorphic hierarchy + would have no 'polymorphic_on' column if it didn't also + specify a 'polymorphic_identity', leading to strange + errors upon refresh, wrong class loaded when querying + from that target. [ticket:2038] + - sql - Column.copy(), as used in table.tometadata(), copies the 'doc' attribute. [ticket:2028] diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index c7e93c19d9..63d2c4de94 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -305,16 +305,17 @@ class Mapper(object): if self.polymorphic_identity is not None: self.polymorphic_map[self.polymorphic_identity] = self - if self.polymorphic_on is None: - for mapper in self.iterate_to_root(): - # try to set up polymorphic on using - # correesponding_column(); else leave - # as None - if mapper.polymorphic_on is not None: - self.polymorphic_on = \ - self.mapped_table.corresponding_column( - mapper.polymorphic_on) - break + + if self.polymorphic_on is None: + for mapper in self.iterate_to_root(): + # try to set up polymorphic on using + # correesponding_column(); else leave + # as None + if mapper.polymorphic_on is not None: + self.polymorphic_on = \ + self.mapped_table.corresponding_column( + mapper.polymorphic_on) + break else: self._all_tables = set() self.base_mapper = self diff --git a/test/ext/test_declarative.py b/test/ext/test_declarative.py index d236cc3ab6..cc743843f1 100644 --- a/test/ext/test_declarative.py +++ b/test/ext/test_declarative.py @@ -1187,7 +1187,8 @@ class DeclarativeInheritanceTest(DeclarativeTestBase): primary_language = Column(String(50)) assert 'inherits' not in Person.__mapper_args__ - assert class_mapper(Engineer).polymorphic_on is None + assert class_mapper(Engineer).polymorphic_identity is None + assert class_mapper(Engineer).polymorphic_on is Person.__table__.c.type def test_custom_join_condition(self): diff --git a/test/orm/inheritance/test_basic.py b/test/orm/inheritance/test_basic.py index 7257cbd791..55cc439935 100644 --- a/test/orm/inheritance/test_basic.py +++ b/test/orm/inheritance/test_basic.py @@ -1516,6 +1516,50 @@ class PKDiscriminatorTest(_base.MappedTest): assert a.name=='a1new' assert p.name=='p1new' +class NoPolyIdentInMiddleTest(_base.MappedTest): + @classmethod + def define_tables(cls, metadata): + Table('base', metadata, + Column('id', Integer, primary_key=True, test_needs_autoincrement=True), + Column('type', String(50), nullable=False), + ) + + @classmethod + def setup_classes(cls): + class A(_base.BasicEntity): + pass + class B(A): + pass + class C(B): + pass + + @classmethod + @testing.resolve_artifact_names + def setup_mappers(cls): + mapper(A, base, polymorphic_on=base.c.type) + mapper(B, inherits=A) + mapper(C, inherits=B, polymorphic_identity='c') + + @testing.resolve_artifact_names + def test_load_from_middle(self): + s = Session() + s.add(C()) + o = s.query(B).first() + eq_(o.type, 'c') + assert isinstance(o, C) + + @testing.resolve_artifact_names + def test_load_from_base(self): + s = Session() + s.add(C()) + o = s.query(A).first() + eq_(o.type, 'c') + assert isinstance(o, C) + + @testing.resolve_artifact_names + def test_discriminator(self): + assert class_mapper(B).polymorphic_on is base.c.type + assert class_mapper(C).polymorphic_on is base.c.type class DeleteOrphanTest(_base.MappedTest): """Test the fairly obvious, that an error is raised @@ -1526,7 +1570,6 @@ class DeleteOrphanTest(_base.MappedTest): """ - @classmethod def define_tables(cls, metadata): global single, parent