the usage of "classproperty" here suggests you're using SQLAlchemy's internal function, which has special meaning in that it gets treated like declared_attr, and you can see in INSERT it is using HybridModel for everyone. Using a different classproperty approach below the test case passes.

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.ext.hybrid import hybrid_property, Comparator

Base = declarative_base()

class classproperty(property):
    """A decorator that behaves like @property except that operates
    on classes rather than instances.

    The decorator is currently special when using the declarative
    module, but note that the
    :class:`~.sqlalchemy.ext.declarative.declared_attr`
    decorator should be used for this purpose with declarative.

    """

    def __init__(self, fget, *arg, **kw):
        super(classproperty, self).__init__(fget, *arg, **kw)
        self.__doc__ = fget.__doc__

    def __get__(desc, self, cls):
        return desc.fget(cls)


class ModelBase(Base):
    __abstract__ = True

    def __repr__(self):
        return "{} ({}:{})".format(type(self).__name__, self.name, self.id)


class HybridType(ModelBase):
    __tablename__ = 'hybrid_types'
    id = Column(Integer, primary_key=True)
    name = Column(Text)


class HybridModel(ModelBase):
    __tablename__ = 'hybrids'

    id = Column(Integer, primary_key=True)
    name = Column(Text)
hybrid_type_id = Column(Integer, ForeignKey('hybrid_types.id'), nullable=False)
    hybrid_type = relationship('HybridType')

    def __init__(self, *args, **kwargs):
        self.hybrid_type_name = self.hybrid_type_identity
        return super().__init__(*args, **kwargs)

    @classproperty
    def hybrid_type_identity(cls):
        return cls.__name__

    @declared_attr
    def __mapper_args__(cls):
        return dict(
            polymorphic_on=cls.hybrid_type_name_subquery(),
            polymorphic_identity=cls.hybrid_type_identity,
        )

    @hybrid_property
    def hybrid_type_name(self):
        return self.hybrid_type.name

    @hybrid_type_name.setter
    def hybrid_type_name(self, value):
        self.hybrid_type_id = (
            select([HybridType.id]).
            where(HybridType.name == value)
        )

    @hybrid_type_name.expression
    def hybrid_type_name(cls):
        return cls.hybrid_type_name_subquery()

    @classmethod
    def hybrid_type_name_subquery(cls):
return select([HybridType.name]).where(HybridType.id == cls.hybrid_type_id).as_scalar()

    class HybridComparator(Comparator):

        def operate(self, op, other):
return op(HybridType.hybrid_type_id, select([HybridType.id]).where(HybridType.name == other).as_scalar())

    @hybrid_type_name.comparator
    def hybrid_type_name(cls):
        return cls.HybridComparator(cls)


class HybridAlpha(HybridModel):
    pass


class Hybrita(HybridModel):
    pass


e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
session = Session(e)


session.add(HybridType(name=HybridAlpha.hybrid_type_identity))
session.add(HybridType(name=Hybrita.hybrid_type_identity))
session.add(HybridAlpha(name='alpha_instance'))
session.add(Hybrita(name='beta_instance'))


all_alphas = session.query(HybridAlpha).all()
assert session.query(HybridModel).count() == 2
print("------")
assert session.query(HybridAlpha).count() == 1
assert session.query(Hybrita).count() == 1




On 12/29/2016 11:09 AM, Tucker Beck wrote:
Mike,

Here's the solution I came up with. It shows the 'inverted select' used
in the comparator vs the hybrid expression

class ModelBase(db.Model):
    __abstract__ = True

    def __repr__(self):
        return "{} ({}:{})".format(type(self).__name__, self.name
<http://self.name>, self.id <http://self.id>)


class HybridType(ModelBase):
    __tablename__ = 'hybrid_types'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)


class HybridModel(ModelBase):
    __tablename__ = 'hybrids'

    id = db.Column(db.BigInteger, primary_key=True)
    name = db.Column(db.Text)
    hybrid_type_id = db.Column(db.Integer,
db.ForeignKey('hybrid_types.id <http://hybrid_types.id>'), nullable=False)
    hybrid_type = db.relationship('HybridType')

    def __init__(self, *args, **kwargs):
        self.hybrid_type_name = self.hybrid_type_identity
        return super().__init__(*args, **kwargs)

    @classproperty
    def hybrid_type_identity(cls):
        return inflection.underscore(cls.__name__)

    @declared_attr
    def __mapper_args__(cls):
        return dict(
            polymorphic_on=cls.hybrid_type_name_subquery(),
            polymorphic_identity=cls.hybrid_type_identity,
        )

    @hybrid_property
    def hybrid_type_name(self):
        return self.hybrid_type.name <http://self.hybrid_type.name>

    @hybrid_type_name.setter
    def hybrid_type_name(self, value):
        self.hybrid_type_id = (
            select([HybridType.id]).
            where(HybridType.name == value)
        )

    @hybrid_type_name.expression
    def hybrid_type_name(cls):
        return cls.hybrid_type_name_subquery()

    @classmethod
    def hybrid_type_name_subquery(cls):
        return select([HybridType.name]).where(HybridType.id ==
cls.hybrid_type_id).as_scalar()


    class HybridComparator(Comparator):

        def operate(self, op, other):
            return op(HybridType.hybrid_type_id,
select([HybridType.id]).where(HybridType.name == other).as_scalar())


    @hybrid_type_name.comparator
    def hybrid_type_name(cls):
        return cls.HybridComparator(cls)


class HybridAlpha(HybridModel):
    pass


class HybridBeta(HybridModel):
    pass


class TestHybrids:

    def test_all_query(self):
        db.session.add(HybridType(name=HybridAlpha.hybrid_type_identity))
        db.session.add(HybridType(name=HybridBeta.hybrid_type_identity))
        db.session.add(HybridAlpha(name='alpha_instance'))
        db.session.add(HybridBeta(name='beta_instance'))
        all_alphas = HybridAlpha.query.all()
        assert HybridModel.query.count() == 2
        assert HybridAlpha.query.count() == 1
        assert HybridBeta.query.count() == 1


On Wed, Dec 28, 2016 at 2:19 PM, mike bayer <mike...@zzzcomputing.com
<mailto:mike...@zzzcomputing.com>> wrote:



    On 12/27/2016 04:36 PM, Tucker Beck wrote:

        Mike (or whoever else might have insight):

        I used the pattern above, and it worked great until I tried use
        it for a
        really large table that I was querying and filtering by the hybrid
        property. Something like this:
        query(HybridModel).filter_by(hybrid_type_name='alpha')


    Well I mentioned a correlated subquery won't scale here.





        The resulting query does a seq-scan applying a sub-select to get the
        hybrid_type_name and then comparing it to the filter value
        ('alpha' in
        the example). Obviously, this is sub-optimal, and I want the
        query to do
        an index-scan comparing the hybrid_type_id matching the
        filter_value to
        the hybrid_type_id of each row. The table has an index on
        hybrid_type_id, so that query is orders of magnitude faster. Before
        using this revised pattern we discussed, I got the query I wanted by
        adding a comparator to my class that basically inverts the
        select used
        by the hybrid property expression. That worked great before
        using this
        pattern.


    I'm not sure what "invert the select" looks like.


        However, with the new pattern, the delcared_attr __mapper_args__
        attempts to use the expression from the comaprator for
        polymorphic_on,
        and that query results in an integer (primary key) which won't work
        because we defined our polymorphic identities using the name


    I'm not understanding this part either, can this be demonstrated
    with the simple test script I gave you ?





        Do you have any ideas on how I might resolve this issue?

        On Sat, Dec 3, 2016 at 4:25 PM, mike bayer
        <mike...@zzzcomputing.com <mailto:mike...@zzzcomputing.com>
        <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>> wrote:



            On 12/01/2016 05:29 PM, Tucker Beck wrote:

                This is what I ended up with, and it *seems* to work pretty
                well. Does
                my approach here pass the sniff test?


            everything looks idiomatic, so if it does what you need,
        then it's
            greatg!




                from sqlalchemy.ext.hybrid import hybrid_property
                from sqlalchemy.ext.declarative import declarative_base,
                declared_attr
                from sqlalchemy.orm import sessionmaker, relationship,
                column_property
                from sqlalchemy import (
                    Column, Integer, ForeignKey, Text,
                    select, create_engine,
                )

                Base = declarative_base()


                class HybridType(Base):
                    __tablename__ = 'hybrid_types'
                    id = Column(Integer, primary_key=True)
                    name = Column(Text)


                class HybridModel(Base):
                    __tablename__ = 'hybrids'
                    hybrid_type_identity = 'base'

                    id = Column(Integer, primary_key=True)
                    name = Column(Text)
                    hybrid_type_id = Column(Integer,
        ForeignKey('hybrid_types.id <http://hybrid_types.id>
                <http://hybrid_types.id>
                <http://hybrid_types.id>'))
                    hybrid_type = relationship('HybridType')

                    @declared_attr
                    def __mapper_args__(cls):
                        return dict(
                            polymorphic_on=cls.hybrid_type_name,
                            polymorphic_identity=cls.hybrid_type_identity,
                        )

                    def __repr__(self):
                        return "{} ({}:{})".format(type(self).__name__,
                self.name <http://self.name> <http://self.name>
                <http://self.name>, self.id <http://self.id>
        <http://self.id> <http://self.id>)

                    def __init__(self, **kwargs):
                        self.hybrid_type_name = self.hybrid_type_identity
                        super(HybridModel, self).__init__(**kwargs)

                    @hybrid_property
                    def hybrid_type_name(self):
                        return self.hybrid_type.name
        <http://self.hybrid_type.name>
                <http://self.hybrid_type.name>
        <http://self.hybrid_type.name>

                    @hybrid_type_name.expression
                    def hybrid_type_name(cls):
                        return (
                            select([HybridType.name]).
                            where(HybridType.id == cls.hybrid_type_id).
                            as_scalar()
                        )

                    @hybrid_type_name.setter
                    def hybrid_type_name(self, value):
                        self.hybrid_type_id = (
                            select([HybridType.id]).
                            where(HybridType.name == value)
                        )


                class HybridAlpha(HybridModel):
                    hybrid_type_identity = 'alpha'


                class HybridBeta(HybridModel):
                    hybrid_type_identity = 'beta'


                engine = create_engine('sqlite:///:memory:', echo=False)
                Base.metadata.create_all(engine)
                Session = sessionmaker(bind=engine)
                session = Session()
                session.add(HybridType(name='base'))
                session.add(HybridType(name='alpha'))
                session.add(HybridType(name='beta'))
                session.add(HybridModel(name='base_instance'))
                session.add(HybridAlpha(name='alpha_instance'))
                session.add(HybridBeta(name='beta_instance'))
                print(session.query(HybridModel).all())
                print(session.query(HybridAlpha).all())
                print(session.query(HybridAlpha).one().hybrid_type_name)
                session.query(HybridAlpha).one().hybrid_type_name = 'beta'
                print(session.query(HybridBeta).all())


                On Wed, Nov 30, 2016 at 7:20 AM, mike bayer
                <mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
        <mailto:mike...@zzzcomputing.com <mailto:mike...@zzzcomputing.com>>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>>> wrote:



                    On 11/29/2016 07:31 PM, Tucker Beck wrote:

                        Thanks for this! What allows the query to filter
        in the
                derived
                        classes
                        when using a column property instead of a hybrid
                property? Is it
                        declaring the __mapper_args__ in the base class
        declaration
                        instead of
                        after it?


                    Yea I don't think setting __mapper_args__ after the
        fact on the
                    class does anything.   Those __mapper_args__ are
        only for the
                    mapper() constructor directly, which gets called
        when the
                class is
                    declared.

                    you can set the actual polymorphic_on property right now
                only using
                    the special
        class.__mapper__._set_polymorphic_on(<something>),
                    that's one of a very few setters that's available on
        the mapper
                    after the fact and even then it's not fully public
        API right
                now.



                        Also, it seems like having the hybrid_type_prop
        column
                property
                        obviates
                        the need for the hybrid property
        hybrid_type_name...that is,
                        except for
                        the setter. Is there a way to give a
        column_property a
                setter?


                    a column_property against a SQL expression is strictly a
                read-only
                    thing, since "writing" to it makes no sense in terms of
                persistence.


                    the column_property aspect here isn't strictly
        necessary,
                the mapper
                    will create the property internally as a special
        case for the
                    polymorphic_on setting if not provided.  the example
        can be
                    re-organized w/ your hybrid in at least two ways:


                    class HybridModel(Base):
                        # ...

                        @declared_attr
                        def __mapper_args__(cls):
                            return {
                                "polymorphic_on": cls.hybrid_type_name
                            }


                    or


                    class HybridModel(Base):
                        # ...

                        _hybrid_name_expr = (
                            select([HybridType.name]).
                            where(HybridType.id == hybrid_type_id).
                            as_scalar()
                        )

                        __mapper_args__ = {
                            "polymorphic_on": _hybrid_name_expr
                        }

                        # ...

                        @hybrid_type_name.expression
                        def hybrid_type_name(cls):
                            return cls._hybrid_name_expr



                        On Tue, Nov 29, 2016 at 2:59 PM, mike bayer
                        <mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
        <mailto:mike...@zzzcomputing.com <mailto:mike...@zzzcomputing.com>>>
                        <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>
                        <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>>>> wrote:



                            On 11/29/2016 05:01 PM, Tucker Beck wrote:

                                The issue with using the foreign_key integer
                value as the
                                discriminator
                                is that you won't know what that is at class
                declaration
                        time. The
                                type_name, however, you can declare as a
        part of the
                        class as
                                you would
                                with a normal string discriminator. I'm
        not sure
                how you
                        would do a
                                correlated subquery for the polymorphic_on
                attribute. I
                        modified the
                                query object so that I could filter
        results for
                the derived
                                classes. It
                                doesn't seem like that happens
        automatically.
                Maybe I'm
                        just not
                                doing
                                it right.


                            The correlated subquery will not scale as
        well as a
                direct
                            identifier, but here is an adaption of your
        test using
                            column_property(), and you should be able to set
                        polymorphic_on to
                            the select() object directly too.  There's
        another
                example
                        of this
                            at



        
http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on
        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on>

        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on
        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on>>


        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on
        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on>

        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on
        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on>>>



        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on
        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on>

        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on
        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on>>


        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on
        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on>

        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on
        
<http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html?highlight=polymorphic_on#sqlalchemy.orm.mapper.params.polymorphic_on>>>>.

                            For the "use the id" approach, you would need to
                query from
                            HybridType up front and populate the
                polymorphic_identity
                        attributes
                            after the fact, this is a feature that is
        not directly
                        supported yet
                            but there is a recipe to do so at



        
https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity
        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity>

        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity
        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity>>


        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity
        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity>

        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity
        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity>>>



        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity
        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity>

        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity
        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity>>


        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity
        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity>

        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity
        
<https://bitbucket.org/zzzeek/sqlalchemy/issues/2792/settable-polymorphic-identity>>>>.



                            from sqlalchemy.ext.hybrid import
        hybrid_property
                            from sqlalchemy.ext.declarative import
        declarative_base
                            from sqlalchemy.orm import sessionmaker,
        relationship,
                        column_property
                            from sqlalchemy import (
                                Column, Integer, ForeignKey, Text,
                                select, create_engine,
                            )

                            Base = declarative_base()


                            class HybridType(Base):
                                __tablename__ = 'hybrid_types'
                                id = Column(Integer, primary_key=True)
                                name = Column(Text)


                            class HybridModel(Base):
                                __tablename__ = 'hybrids'

                                id = Column(Integer, primary_key=True)
                                name = Column(Text)
                                hybrid_type_id = Column(Integer,
                        ForeignKey('hybrid_types.id
        <http://hybrid_types.id> <http://hybrid_types.id>
                <http://hybrid_types.id>
                            <http://hybrid_types.id>'))
                                hybrid_type = relationship('HybridType')

                                hybrid_type_prop = column_property(
                                    select([HybridType.name]).
                                    where(HybridType.id == hybrid_type_id).
                                    as_scalar()
                                )

                                __mapper_args__ = {
                                    "polymorphic_on": hybrid_type_prop
                                }

                                def __repr__(self):
                                    return "{}
        ({}:{})".format(type(self).__name__,
                        self.name <http://self.name> <http://self.name>
        <http://self.name>
                            <http://self.name>, self.id <http://self.id>
        <http://self.id>
                <http://self.id> <http://self.id>)

                                def __init__(self, **kwargs):
                                    self.hybrid_type_name =

        type(self).__mapper_args__['polymorphic_identity']
                                    super(HybridModel,
        self).__init__(**kwargs)

                                @hybrid_property
                                def hybrid_type_name(self):
                                    return self.hybrid_type.name
        <http://self.hybrid_type.name>
                <http://self.hybrid_type.name>
                        <http://self.hybrid_type.name>
                <http://self.hybrid_type.name>

                                @hybrid_type_name.setter
                                def hybrid_type_name(self, value):
                                    self.hybrid_type_id = (
                                        select([HybridType.id]).
                                        where(HybridType.name == value)
                                    )


                            class HybridAlpha(HybridModel):
                                __mapper_args__ =
        {'polymorphic_identity': 'alpha'}


                            class HybridBeta(HybridModel):
                                __mapper_args__ =
        {'polymorphic_identity': 'beta'}


                            engine = create_engine('sqlite:///:memory:',
        echo=True)
                            Base.metadata.create_all(engine)
                            Session = sessionmaker(bind=engine)
                            session = Session()
                            session.add(HybridType(name='alpha'))
                            session.add(HybridType(name='beta'))
                            session.add(HybridAlpha(name='alpha_instance'))
                            session.add(HybridBeta(name='beta_instance'))
                            print(session.query(HybridAlpha).all())



                                On Tue, Nov 29, 2016 at 7:16 AM, mike bayer
                                <mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>
                        <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>>
                        <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
        <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>>>
                                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>
                        <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>>

                                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>
                        <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>
                <mailto:mike...@zzzcomputing.com
        <mailto:mike...@zzzcomputing.com>>>>>> wrote:



                                    On 11/28/2016 05:58 PM, Tucker Beck
        wrote:

                                        Hello, I'm writing today about an
                interesting
                        problem we ran
                                        into with
                                        our sqlalchemy based data store api.

                                        Our schema is based on the
        star-schema idea
                        where we have a
                                        large 'fact
                                        table' with lots of rows. Within
        that table,
                        each row has a
                                        foreign key
                                        to a small 'dimension table' in
        which
                each row
                        has a unique
                                        name. Thus,
                                        the type of each row can be
        defined by the
                        relationship
                                between
                                        the fact
                                        row and the dimension row.

                                        We wanted to be able to use
        SQLAlchemy
                to add
                        some custom
                                        functionality
                                        for the different types of rows
        we have
                in our 'fact
                                table'. After
                                        learning about SQLAlchemy's
        inheritance
                models, I
                                decided to see
                                        if we
                                        could support the schema that we
        had already
                        devised for our
                                        project.
                                        The single-inheritance pattern
        seemed to
                fit the
                        best, but I
                                        couldn't
                                        find a single case where someone
        was using a
                        star-schema and
                                        needed the
                                        type discriminator to be derived
        from the
                        foreign key to the
                                        dimension
                                        table.

                                        Further, I found as I was
        digging into the
                        mechanics of the
                                        thing that
                                        you could not create a row in
        the fact table
                        that was
                                typed by the
                                        derived class at creation time.
        And, you
                cannot
                        limit
                                queries
                                        from the
                                        fact table by creating the queries
                against the
                        derived
                                classes.
                                        Suppose
                                        that (using declarative base) I
        have the
                fact table
                                represented by a
                                        model called HybridModel. This
        model has two
                        derived classes
                                        HybridAlpha
                                        and HybridBeta. I would like to
        be able to
                        create a new
                                row in
                                        the table
                                        wrapped by HybridModel by calling
                something like
                                        HybridAlpha(**kwargs)
                                        and have the type of the new row
        reflect the
                        inheritance
                                model I've
                                        described above. Next I wanted
        to be able to
                        formulate a
                                query
                                        against
                                        one of the derived models and
        have it
                limited by the
                                type associated
                                        with the derived class. So, calling
                something like

        `session.query(HybridAlpha).all()` would
                only return
                                rows with a
                                        type
                                        associated with the HybridAlpha
        model.

                                        After a lot of tinkering and
                experimentation,
                        I've come
                                up with the
                                        following solution:





        https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>

        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>>


        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>

        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>>>



        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>

        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>>


        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>

        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        
<https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>>>>




        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>

        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>>


        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>

        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>>>



        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>

        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>>


        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>

        <https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89
        
<https://gist.github.com/dusktreader/2658dedb8ca8e2fd941f8075c75b3c89>>>>>

                                        I would appreciate any thoughts and
                feedback on the
                                matter. I'm
                                        not sure
                                        that my approach to this
        solution has been
                        sound, and I
                                would
                                        appreciate
                                        feedback.


                                    I'd try to do things much more
        simply than
                this.   Most
                                simply, just
                                    assign polymorphic_identity to be
        the integer
                        foreign key value.
                                    Otherwise, you should be able to do
                polymorphic_on on a
                                correlated
                                    subquery, which itself you set up as a
                        column_property().
                                 There
                                    should be no need to modify Query or
                anything like that.


                                    I'm out of time today but if you
        need more
                help I
                        can try to
                                work up
                                    an example later on.






                                        Thanks, and keep up the great work!
                SQLAlchemy
                        is just
                                magic!

                                        --
                                        SQLAlchemy -
                                        The Python SQL Toolkit and Object
                Relational Mapper

                                        http://www.sqlalchemy.org/

                                        To post example code, please
        provide an
                MCVE:
                        Minimal,
                                Complete, and
                                        Verifiable Example. See
                                http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>
                        <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>>
                                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>
                        <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>>>

        <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>
                        <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>>
                                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>
                        <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>>>> for a full
                                        description.
                                        ---
                                        You received this message
        because you are
                        subscribed to
                                the Google
                                        Groups "sqlalchemy" group.
                                        To unsubscribe from this group
        and stop
                        receiving emails
                                from
                                        it, send
                                        an email to
                        sqlalchemy+unsubscr...@googlegroups.com
        <mailto:sqlalchemy%2bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%2bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com>>

        <mailto:sqlalchemy%2bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>>>

                <mailto:sqlalchemy%2bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>>

        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com>>>>


        <mailto:sqlalchemy%2bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>>

        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com>>>

                <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com>>

        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252525252bunsubscr...@googlegroups.com>>>>>

                <mailto:sqlalchemy+unsubscr...@googlegroups.com
        <mailto:sqlalchemy%2bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%2bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com>>

        <mailto:sqlalchemy%2bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>>>

                <mailto:sqlalchemy%2bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>>

        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com>>>>


        <mailto:sqlalchemy%2bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>>

        <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com>>>

                <mailto:sqlalchemy%252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com>>

        <mailto:sqlalchemy%25252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com>
                <mailto:sqlalchemy%2525252bunsubscr...@googlegroups.com
        <mailto:sqlalchemy%252525252bunsubscr...@googlegroups.com>>>>>>.

                                        To post to this group, send email to
                                sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>>>

        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>>
                                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>>>>

        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>>
                                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>>>

        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>>
                                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>
                        <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>
                <mailto:sqlalchemy@googlegroups.com
        <mailto:sqlalchemy@googlegroups.com>>>>>>.
                                        Visit this group at

        https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>
                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>>
                        <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>
                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>>>

        <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>
                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>>
                        <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>
                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>>>>

                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>
                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>>
                        <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>
                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>>>

        <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>
                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>>
                        <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>
                <https://groups.google.com/group/sqlalchemy
        <https://groups.google.com/group/sqlalchemy>>>>>.
                                        For more options, visit
                                https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>
                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>>
                        <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>
                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>>>
                                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>
                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>>
                        <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>
                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>>>>

        <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>
                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>>
                        <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>
                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>>>
                                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>
                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>>
                        <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>
                <https://groups.google.com/d/optout
        <https://groups.google.com/d/optout>>>>>.


                                    --
                                    SQLAlchemy - The Python SQL Toolkit
        and Object
                        Relational Mapper

                                    http://www.sqlalchemy.org/

                                    To post example code, please provide an
                MCVE: Minimal,
                                Complete, and
                                    Verifiable Example.  See
                        http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>
                        <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>>
                                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>
                        <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>>>
                                    <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>
                <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>>
                        <http://stackoverflow.com/help/mcve
        <http://stackoverflow.com/help/mcve>




--
-=Tucker A. Beck=-

Illustrious Writer
  Devious Coder
    Last Hope for the Free World
      Also, Modest

--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and
Verifiable Example. See http://stackoverflow.com/help/mcve for a full
description.
---
You received this message because you are subscribed to the Google
Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to sqlalchemy+unsubscr...@googlegroups.com
<mailto:sqlalchemy+unsubscr...@googlegroups.com>.
To post to this group, send email to sqlalchemy@googlegroups.com
<mailto:sqlalchemy@googlegroups.com>.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

--
SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to