auto-aliasing for cls->joined-inh only considers the previous class

Issue #2903 resolved
Mike Bayer repo owner created an issue

I thought the auto-aliasing from query(B).join(B.cs) if C were joined-inh was removed. but it's not. so now it only takes into account the immediate joinpoint, and fails in a case like this:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class A(Base):
    __tablename__ = 'a'

    id = Column(Integer, primary_key=True)


class B(A):
    __tablename__ = 'b'

    id = Column(Integer, ForeignKey('a.id'), primary_key=True)
    c_id = Column(Integer, ForeignKey('c.id'))
    c = relationship("C", foreign_keys=c_id)

class C(A):
    __tablename__ = 'c'

    id = Column(Integer, ForeignKey('a.id'), primary_key=True)
    d_id = Column(Integer, ForeignKey('d.id'))
    d = relationship("D", foreign_keys=d_id)

class D(A):
    __tablename__ = 'd'

    id = Column(Integer, ForeignKey('a.id'), primary_key=True)
    e_id = Column(Integer, ForeignKey('e.id'))
    e = relationship("E", foreign_keys=e_id)

class E(A):
    __tablename__ = 'e'

    id = Column(Integer, ForeignKey('a.id'), primary_key=True)
    f_id = Column(Integer, ForeignKey('f.id'))
    f = relationship("F", foreign_keys=f_id)

class F(A):
    __tablename__ = 'f'

    id = Column(Integer, ForeignKey('a.id'), primary_key=True)

e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
Base.metadata.create_all(e)
s = Session(e)

s.query(B).join("c", "d", "e", "f").all()

Comments (3)

  1. Mike Bayer reporter

    patch:

    diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
    index 4f10a6a..b1916b9 100644
    --- a/lib/sqlalchemy/orm/query.py
    +++ b/lib/sqlalchemy/orm/query.py
    @@ -1847,9 +1847,13 @@ class Query(object):
             l_info = inspect(left)
             r_info = inspect(right)
    
    -        overlap = not create_aliases and \
    -                        sql_util.selectables_overlap(l_info.selectable,
    -                            r_info.selectable)
    +        overlap = False
    +        if not create_aliases:
    +            for from_obj in self._from_obj or [l_info.selectable](l_info.selectable):
    +                if sql_util.selectables_overlap(from_obj, r_info.selectable):
    +                    overlap = True
    +                    break
    +
             if overlap and l_info.selectable is r_info.selectable:
                 raise sa_exc.InvalidRequestError(
                         "Can't join table/selectable '%s' to itself" %
    
  2. Log in to comment