Consider the following configuration:
class Employee(Base):
__tablename__ = "employee"
id = Column(Integer, primary_key=True)
type = Column(String(100))
cars = relationship("Car")
__mapper_args__ = {
"polymorphic_on": type,
}
class Car(Base):
__tablename__ = "car"
id = Column(Integer, primary_key=True)
employee_id = Column(Integer, ForeignKey(Employee.id))
class Engineer(Employee):
__tablename__ = "engineer"
id = Column(Integer, ForeignKey(Employee.id), primary_key=True)
specialty = Column(String(100))
__mapper_args__ = {
"polymorphic_identity": "engineer",
}
And the following query:
session.add(Engineer())
session.flush()
E = with_polymorphic(Employee, [Engineer])
session.query(E).options(subqueryload(E.cars)).order_by(Engineer.specialty).first()
This results in the following exception:
Traceback (most recent call last):
File "test.py", line 50, in main
.order_by(Engineer.specialty).first()
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2334, in first
ret = list(self[0:1])
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2201, in __getitem__
return list(res)
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 72, in instances
rows = [process[0](row, None) for row in fetch]
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 350, in _instance
return _instance(row, result)
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 455, in _instance
populate_state(state, dict_, row, isnew, only_load_props)
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 305, in populate_state
populator(state, dict_, row)
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/strategies.py", line 1004, in load_collection_from_subq
()
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/strategies.py", line 951, in get
self._load()
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/strategies.py", line 959, in _load
lambda x: x[1:]
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2405, in __iter__
return self._execute_and_instances(context)
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2420, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 727, in execute
return meth(self, multiparams, params)
File "/usr/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 322, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 824, in _execute_clauseelement
compiled_sql, distilled_params
File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 954, in _execute_context
context)
File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1116, in _handle_dbapi_exception
exc_info
File "/usr/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 189, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 947, in _execute_context
context)
File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 435, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (ProgrammingError) missing FROM-clause entry for table "engineer"
LINE 3: FROM employee ORDER BY engineer.specialty
^
'SELECT car.id AS car_id, car.employee_id AS car_employee_id, anon_1.employee_id AS anon_1_employee_id \nFROM (SELECT employee.id AS employee_id \nFROM employee ORDER BY engineer.specialty \n LIMIT %(param_1)s) AS anon_1 JOIN car ON anon_1.employee_id = car.employee_id ORDER BY anon_1.employee_id' {'param_1': 1}
It looks like SQLAlchemy cannot figure out that the subquery needs to include a join to engineer. Is there some magical incantation that would make it work?
Curiously, a many-to-one relationship works:
class Car(Base):
__tablename__ = "car"
id = Column(Integer, primary_key=True)
class Employee(Base):
__tablename__ = "employee"
id = Column(Integer, primary_key=True)
type = Column(String(100))
car_id = Column(Integer, ForeignKey(Car.id))
car = relationship(Car)
__mapper_args__ = {
"polymorphic_on": type,
}
class Engineer(Employee):
__tablename__ = "engineer"
id = Column(Integer, ForeignKey(Employee.id), primary_key=True)
specialty = Column(String(100))
__mapper_args__ = {
"polymorphic_identity": "engineer",
}
session.add(Engineer())
session.flush()
E = with_polymorphic(Employee, [Engineer])
session.query(E).options(subqueryload(E.car)).order_by(Engineer.specialty).first()
The compiled query:
SELECT car.id AS car_id, anon_1.employee_car_id AS anon_1_employee_car_id
FROM (SELECT DISTINCT employee.car_id AS employee_car_id, engineer.specialty AS engineer_specialty
FROM employee, engineer ORDER BY engineer.specialty
LIMIT %(param_1)s) AS anon_1 JOIN car ON car.id = anon_1.employee_car_id ORDER BY anon_1.employee_car_id
{'param_1': 1}