- changed status to resolved
allow of_type() strategies to be stacked
Issue #3256
resolved
from sqlalchemy import Integer, ForeignKey, String, Column, create_engine
from sqlalchemy.orm import relationship, joinedload, with_polymorphic, Session
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
import logging
logging.basicConfig()
logging.getLogger("sqlalchemy.orm.path_registry").setLevel(logging.DEBUG)
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
b_id = Column(ForeignKey('b.id'))
b = relationship("B")
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
type = Column(String)
__mapper_args__ = {
'polymorphic_on': type,
}
class BSub1(B):
__mapper_args__ = {
'polymorphic_identity': 'sub1',
}
c = relationship("C1", uselist=False)
class BSub2(B):
__mapper_args__ = {
'polymorphic_identity': 'sub2',
}
c = relationship("C2", uselist=False)
class C1(Base):
__tablename__ = 'c1'
id = Column(Integer, primary_key=True)
b_id = Column(ForeignKey('b.id'))
class C2(Base):
__tablename__ = 'c2'
id = Column(Integer, primary_key=True)
b_id = Column(ForeignKey('b.id'))
e = create_engine("sqlite://", echo='debug')
Base.metadata.create_all(e)
s = Session(e)
s.add_all([
A(b=BSub1(c=C1())),
A(b=BSub2(c=C2()))
])
s.commit()
b_poly = with_polymorphic(B, [BSub1, BSub2], aliased=True)
q = s.query(A).options(
# works
# joinedload(A.b.of_type(b_poly)).joinedload(b_poly.BSub1.c),
# joinedload(A.b.of_type(b_poly)).joinedload(b_poly.BSub2.c),
# fails, eager loads only one of them
joinedload(A.b.of_type(BSub1)).joinedload(BSub1.c),
joinedload(A.b.of_type(BSub2)).joinedload(BSub2.c),
)
for a in q:
b = a.b
print b.c
Comments (1)
-
reporter - Log in to comment
.PropComparator.of_type
modifier has been improved in conjunction with loader directives such as :func:.joinedload
and :func:.contains_eager
such that if two :meth:.PropComparator.of_type
modifiers of the same base type/path are encountered, they will be joined together into a single "polymorphic" entity, rather than replacing the entity of type A with the one of type B. E.g. a joinedload ofA.b.of_type(BSub1)->BSub1.c
combined with joinedload ofA.b.of_type(BSub2)->BSub2.c
will create a single joinedload ofA.b.of_type((BSub1, BSub2)) -> BSub1.c, BSub2.c
, without the need for thewith_polymorphic
to be explicit in the query. fixes#3256→ <<cset de11f9498258>>