On Sep 23, 2013, at 8:35 AM, Philip Scott <safetyfirstp...@gmail.com> wrote:


this is normal, loading for the base class only hits those columns which are defined for that base class - it does not automatically fan out to all columns mapped by all subclasses. 
to do so, you can specify with_polymorphic:
 
Ahh, thank you very much Michael that does do exactly what I want. So many times in SQLAlchemy I have been rummaging and hacking for days and then there's a simple one liner that does exactly what I was after all along :)

One problem remains though. I use a Query.from_self() which seems to cause SA to forget about the with_polymorphic setting I have given in mapper_args.

this sounds like a bug but I can't reproduce.   Attached is a full series of tests for both mapper-level and entity-level with_polymorphic, if you can illustrate your usage within this series of tests where mapper level with_polymorphic is erased by from_self(), we can identify it.



If I try to remind it, by explicitly saying my_query.with_polymorphic("*") I get errors like this:

> Query.with_polymorphic() being called on a Query with existing criterion. 

Which seems to be related in some way to having a .distinct or .order_by clause in the query. Is this expected/understood? 

yes, you should use the freestanding with_polymorphic() for greater flexibility.



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

class WPFromSelfTest(unittest.TestCase):
    def _fixture(self, wp=None):
        Base = declarative_base()

        class A(Base):
            __tablename__ = 'a'

            id = Column(Integer, primary_key=True)
            type = Column(String)

            __mapper_args__ = {
                                'polymorphic_on': type,
                                "with_polymorphic": wp}

        class B(A):
            __mapper_args__ = {'polymorphic_identity': 'b'}
            x = Column(String)

        class C(A):
            __mapper_args__ = {'polymorphic_identity': 'c'}
            y = Column(String)

        self.engine = create_engine("sqlite://", echo=True)
        Base.metadata.create_all(self.engine)
        s = Session(self.engine)
        s.add_all([B(x='b1'), C(y='c1')])
        s.commit()

        return A, B, C

    def test_control(self):
        A, B, C = self._fixture()
        s = Session(self.engine)
        q = s.query(A).order_by(A.id)
        r = q.all()
        assert 'x' not in r[0].__dict__
        assert 'y' not in r[1].__dict__

    def test_control_from_self(self):
        A, B, C = self._fixture()
        s = Session(self.engine)
        q = s.query(A).order_by(A.id)
        q = q.from_self()
        r = q.all()
        assert 'x' not in r[0].__dict__
        assert 'y' not in r[1].__dict__

    def test_per_q_wp(self):
        A, B, C = self._fixture()

        s = Session(self.engine)
        wp = with_polymorphic(A, [B, C])
        q = s.query(wp).order_by(wp.id)
        r = q.all()
        assert 'x' in r[0].__dict__
        assert 'y' in r[1].__dict__

    def test_per_q_wp_from_self(self):
        A, B, C = self._fixture()

        s = Session(self.engine)
        wp = with_polymorphic(A, [B, C])
        q = s.query(wp).order_by(wp.id)
        q = q.from_self()
        r = q.all()
        assert 'x' in r[0].__dict__
        assert 'y' in r[1].__dict__

    def test_mapper_wp(self):
        A, B, C = self._fixture(wp="*")
        s = Session(self.engine)
        q = s.query(A).order_by(A.id)
        r = q.all()
        assert 'x' in r[0].__dict__
        assert 'y' in r[1].__dict__

    def test_mapper_wp_from_self(self):
        A, B, C = self._fixture(wp="*")
        s = Session(self.engine)
        q = s.query(A).order_by(A.id)
        q = q.from_self()
        r = q.all()
        assert 'x' in r[0].__dict__
        assert 'y' in r[1].__dict__

if __name__ == '__main__':
    unittest.main()

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to