diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-02-02 18:10:07 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-02-02 18:10:07 -0500 |
commit | c5b4938a9a2918a14397cff3edcee8c69ca249ea (patch) | |
tree | d9d4dd5e3d4ad74c2ba271dc36dcc6373854c759 | |
parent | 5a2c332f5e2faf321a89e93d5d183d7ec3767084 (diff) | |
download | sqlalchemy-c5b4938a9a2918a14397cff3edcee8c69ca249ea.tar.gz |
- 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]
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 21 | ||||
-rw-r--r-- | test/ext/test_declarative.py | 3 | ||||
-rw-r--r-- | test/orm/inheritance/test_basic.py | 45 |
4 files changed, 63 insertions, 12 deletions
@@ -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 c7e93c19d..63d2c4de9 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 d236cc3ab..cc743843f 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 7257cbd79..55cc43993 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 |