Load options aren't looking at the superclass
If a query is made on an alias then the load_only
option fails to exclude properties that are set on a base class of the aliased mapper.
q = sess.query(alias).options(load_only("age"))
This is demonstrated in a test case here: https://github.com/malthe/sqlalchemy/tree/load-only-with-alias-issue
Comments (14)
-
repo owner -
reporter Actually I failed to reproduce the actual problem in this test case.
But there is an issue which is that the alias results in a subselect that lists all the columns in the mapper even though they're not part of the column selection:
select a, b from (select a, b, c from foo join bar on ...)
Note how
c
is not in the result, but it's still being listed in the subselect. -
repo owner it's time to provide a real test case :). Here's a start:
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) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) s = Session(e)
-
repo owner oh, does your test case show this? I can look there.
-
repo owner hm, I see a fork of SQLAlchemy there. just give me a quick .py script, thanks.
-
reporter yeah here's the diff: https://github.com/malthe/sqlalchemy/commit/dcd43de436bffaf91cce6bd2e7256dcdbb184896
I thought I'd write a test case against the code base.
I run the test via:
./sqla_nose.py -sxv -w orm/test_deferred.py
But I can try and isolate to a simple .py file.
-
repo owner OK, those tests can be helpful when I put the fix in but I need to understand the issue first (I'm fixing something else right now).
-
reporter Here's a snippet that does demonstrate the issue:
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) a_name = Column(String) class B(A): __tablename__ = 'b' id = Column(Integer, ForeignKey("a.id"), primary_key=True) b_name = Column(String) class C(Base): __tablename__ = 'c' id = Column(Integer, primary_key=True) c_name = Column(String) b_id = Column("b_id", Integer, ForeignKey("b.id")) b = relationship(B) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) s = Session(e) b = B(id=1, a_name="foo", b_name="bar") s.add(b) c = C(id=1, b_id=b.id, c_name="boo") s.add(c) s.flush() print s.query(C).join(B).options( contains_eager(C.b).load_only("id") )
Note how
a.a_name
is included, butb.b_name
is correctly excluded. -
repo owner ok, so is this the bug?
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) a_name = Column(String) class B(A): __tablename__ = 'b' id = Column(Integer, ForeignKey("a.id"), primary_key=True) b_name = Column(String) s = Session() print s.query(B).options(load_only(B.id))
it isn't looking at the superclass. can we rename this issue then? This is all I'm looking at so far.
SELECT b.id AS b_id, a.id AS a_id, a.a_name AS a_a_name FROM a JOIN b ON a.id = b.id
-
reporter I think that's the bug. Let me rename the issue.
-
reporter - changed title to Load options aren't looking at the superclass
-
repo owner - changed status to resolved
- The "wildcard" loader options, in particular the one set up by
the :func:
.orm.load_only
option to cover all attributes not explicitly mentioned, now takes into account the superclasses of a given entity, if that entity is mapped with inheritance mapping, so that attribute names within the superclasses are also omitted from the load. Additionally, the polymorphic discriminator column is unconditionally included in the list, just in the same way that primary key columns are, so that even with load_only() set up, polymorphic loading of subtypes continues to function correctly. fixes#3287
→ <<cset b63aae2c232f>>
-
repo owner - The "wildcard" loader options, in particular the one set up by
the :func:
.orm.load_only
option to cover all attributes not explicitly mentioned, now takes into account the superclasses of a given entity, if that entity is mapped with inheritance mapping, so that attribute names within the superclasses are also omitted from the load. Additionally, the polymorphic discriminator column is unconditionally included in the list, just in the same way that primary key columns are, so that even with load_only() set up, polymorphic loading of subtypes continues to function correctly. fixes#3287
(cherry picked from commit b63aae2c232f980a47aa2a635c35dfa45390f451)
Conflicts: lib/sqlalchemy/orm/mapper.py
→ <<cset 11383dae8d14>>
- The "wildcard" loader options, in particular the one set up by
the :func:
-
reporter This solves the problem.
- Log in to comment
likely not a bug, you should be using
load_only(alias.age)
. please confirm.