the correlate_except tells it exactly what to "correlate" and what not
to, preventing that "auto-correlation" error.

try it out and then show me how you'd like the SQL to be adjusted
given a particular Query.

On Tue, Oct 31, 2017 at 1:32 PM, Tucker Beck <tucker.b...@gmail.com> wrote:
> I'll try this out. The comparator was put in so that queries comparing the
> hybrid_type_name against a string would do a proper sub-select against the
> EntityType table. If we didn't provide the comparator, the hybrid expression
> was used and the resulting query was orders of magnitude slower. Does adding
> the correlate_except() method in there compel sqlalchemy to do a sub-select?
>
> On Tue, Oct 31, 2017 at 10:19 AM, Mike Bayer <mike...@zzzcomputing.com>
> wrote:
>>
>> that error can be fixed using correlate_except:
>>
>>     @classmethod
>>     def hybrid_type_name_subquery(cls):
>>         return select([HybridType.name]).\
>>             where(HybridType.id == cls.hybrid_type_id).\
>>             correlate_except(HybridType).as_scalar()
>>
>> but now that we're looking at your queries in full, the comparator
>> makes no sense.  It just pulls in HybridType into the FROM clause and
>> makes a broken query with "FROM hybrids, hybrid_types" without them
>> being joined.
>>
>> your tests pass just using plain @expression and keeping the
>> subqueries contained:
>>
>>     @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()
>>
>>
>> for extra protection with correlation, correlate_except looks like this:
>>
>>     @classmethod
>>     def hybrid_type_name_subquery(cls):
>>         return select([HybridType.name]).\
>>             where(HybridType.id == cls.hybrid_type_id).\
>>             correlate_except(HybridType).as_scalar()
>>
>>
>>
>>
>>
>>
>> On Tue, Oct 31, 2017 at 12:18 PM, Tucker Beck <tucker.b...@gmail.com>
>> wrote:
>> > Thanks so much for getting back so fast, Mike!
>> >
>> > For some background: we started with the expression, but then discovered
>> > that the performance we were getting was pretty bad on queries when the
>> > table was large and we were filtering by the hybrid attribute. Postgres
>> > was
>> > doing a sequence-scan, and the plan was pretty bad. So, I learned about
>> > custom comparators, and that helped the  performance for those kind of
>> > queries really dramatically. I didn't realize that the comparator was
>> > not
>> > meant to be used along-side an expression; I thought they served
>> > different
>> > purposes.
>> >
>> > Trying your suggestion worked great for order_by. However, filtering on
>> > the
>> > hybrid attribute is failing with complaints about correlation.
>> >
>> > I revised the code as:
>> >
>> > 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)
>> >         )
>> >
>> >     @classmethod
>> >     def hybrid_type_name_subquery(cls):
>> >         return select([HybridType.name]).where(HybridType.id ==
>> > cls.hybrid_type_id).as_scalar()
>> >
>> >     class HybridComparator(Comparator):
>> >
>> >         def __clause_element__(self):
>> >             return self.expression.hybrid_type_name_subquery()
>> >
>> >         def operate(self, op, other):
>> >             return op(HybridType.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
>> >
>> >
>> > e = create_engine("sqlite://", echo=False)
>> > Base.metadata.create_all(e)
>> > session = Session(e)
>> >
>> >
>> > session.add(HybridType(name=HybridAlpha.hybrid_type_identity))
>> > session.add(HybridType(name=HybridBeta.hybrid_type_identity))
>> > session.add(HybridAlpha(name='alpha_instance'))
>> > session.add(HybridBeta(name='beta_instance'))
>> >
>> >
>> > print("--- Test query from base hybrid model ---")
>> > assert session.query(HybridModel).count() == 2
>> > print("passed")
>> > print("--- Test query from base derived hybrid model ---")
>> > assert session.query(HybridAlpha).count() == 1
>> > assert session.query(HybridBeta).count() == 1
>> > print("passed")
>> > print("--- Test query order_by on hybrid attribute ---")
>> > assert [
>> >     x.hybrid_type_name for x
>> >     in session.query(HybridModel).order_by(HybridModel.hybrid_type_name)
>> > ] == [HybridAlpha.hybrid_type_identity, HybridBeta.hybrid_type_identity]
>> > print("passed")
>> > print("--- Test query filter_by on hybrid attribute ---")
>> > assert
>> >
>> > session.query(HybridModel).filter_by(hybrid_type_name=HybridAlpha.hybrid_type_identity).count()
>> > == 1
>> > print("passed")
>> > print("--- Test query filtered on hybrid attribute ---")
>> > assert session.query(HybridModel).filter(HybridAlpha.hybrid_type_name ==
>> > HybridAlpha.hybrid_type_identity).count() == 1
>> > print("passed")
>> >
>> >
>> > And here's the output
>> >
>> > /venv:cem/ $ python demo.py
>> > --- Test query from base hybrid model ---
>> > passed
>> > --- Test query from base derived hybrid model ---
>> > passed
>> > --- Test query order_by on hybrid attribute ---
>> > passed
>> > --- Test query filter_by on hybrid attribute ---
>> > Traceback (most recent call last):
>> >   File "demo.py", line 124, in <module>
>> >     assert
>> >
>> > session.query(HybridModel).filter_by(hybrid_type_name=HybridAlpha.hybrid_type_identity).correlate(HybridModel).count()
>> > == 1
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> > line 3089, in count
>> >     return self.from_self(col).scalar()
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> > line 2843, in scalar
>> >     ret = self.one()
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> > line 2814, in one
>> >     ret = self.one_or_none()
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> > line 2784, in one_or_none
>> >     ret = list(self)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> > line 2855, in __iter__
>> >     return self._execute_and_instances(context)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> > line 2878, in _execute_and_instances
>> >     result = conn.execute(querycontext.statement, self._params)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/engine/base.py",
>> > line 945, in execute
>> >     return meth(self, multiparams, params)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/elements.py",
>> > line 263, in _execute_on_connection
>> >     return connection._execute_clauseelement(self, multiparams, params)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/engine/base.py",
>> > line 1046, in _execute_clauseelement
>> >     if not self.schema_for_object.is_default else None)
>> >   File "<string>", line 1, in <lambda>
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/elements.py",
>> > line 436, in compile
>> >     return self._compiler(dialect, bind=bind, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/elements.py",
>> > line 442, in _compiler
>> >     return dialect.statement_compiler(dialect, self, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 435, in __init__
>> >     Compiled.__init__(self, dialect, statement, **kwargs)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 216, in __init__
>> >     self.string = self.process(self.statement, **compile_kwargs)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 242, in process
>> >     return obj._compiler_dispatch(self, **kwargs)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py",
>> > line 81, in _compiler_dispatch
>> >     return meth(self, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1738, in visit_select
>> >     text, select, inner_columns, froms, byfrom, kwargs)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1817, in _compose_select_body
>> >     for f in froms])
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1817, in <listcomp>
>> >     for f in froms])
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py",
>> > line 81, in _compiler_dispatch
>> >     return meth(self, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1379, in visit_alias
>> >     asfrom=True, **kwargs) + \
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/annotation.py",
>> > line 80, in _compiler_dispatch
>> >     self, visitor, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py",
>> > line 81, in _compiler_dispatch
>> >     return meth(self, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1716, in visit_select
>> >     for name, column in select._columns_plus_names
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1716, in <listcomp>
>> >     for name, column in select._columns_plus_names
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1488, in _label_select_column
>> >     **column_clause_args
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py",
>> > line 81, in _compiler_dispatch
>> >     return meth(self, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 664, in visit_label
>> >     OPERATORS[operators.as_] + \
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py",
>> > line 81, in _compiler_dispatch
>> >     return meth(self, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 576, in visit_grouping
>> >     return "(" + grouping.element._compiler_dispatch(self, **kwargs) +
>> > ")"
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py",
>> > line 81, in _compiler_dispatch
>> >     return meth(self, **kw)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1685, in visit_select
>> >     froms = self._setup_select_stack(select, entry, asfrom, lateral)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py",
>> > line 1788, in _setup_select_stack
>> >     implicit_correlate_froms=asfrom_froms)
>> >   File
>> >
>> > "/home/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/selectable.py",
>> > line 2843, in _get_display_froms
>> >     "manually." % self)
>> > sqlalchemy.exc.InvalidRequestError: Select statement 'SELECT
>> > hybrid_types.name
>> > FROM hybrid_types, hybrids
>> > WHERE hybrid_types.id = hybrids.hybrid_type_id' returned no FROM clauses
>> > due
>> > to auto-correlation; specify correlate(<tables>) to control correlation
>> > manually.
>> >
>> > I've tried looking for some examples for how to use correlate and tried
>> > stuffing it in a few places and still haven't gotten around this error.
>> > What
>> > am I missing?
>> >
>> > (Thanks again so much for the quick response)
>> >
>> >
>> > On Mon, Oct 30, 2017 at 4:58 PM, Mike Bayer <mike...@zzzcomputing.com>
>> > wrote:
>> >>
>> >> On Mon, Oct 30, 2017 at 6:43 PM, Tucker Beck <tucker.b...@gmail.com>
>> >> wrote:
>> >> > I wrestled through getting a model heirarchy to work with
>> >> > single-table
>> >> > inheritance that is polymorphic on a hybrid attribute on this mailing
>> >> > list a
>> >> > while ago.
>> >> >
>> >> > see:
>> >> > https://groups.google.com/d/topic/sqlalchemy/KJXSHwbhbLA/discussion
>> >> >
>> >> > The problem I'm running into now is that it doesn't seem to work
>> >> > correctly
>> >> > when I want to use the hybrid property for filtering or ordering.
>> >> > This seems to be an issue with auto-correlation, but I can't seem to
>> >> > figure
>> >> > out how to get it working.
>> >> >
>> >> > Here is a runnable example:
>> >>
>> >> OK so lets pdb:
>> >>
>> >> class HybridBeta(HybridModel):
>> >>     pass
>> >>
>> >>
>> >> session = Session()
>> >>
>> >> import pdb
>> >> pdb.set_trace()
>> >>
>> >>
>> >>
>> >> what are we getting from HybridModel.hybrid_type_name:
>> >>
>> >> (Pdb) HybridModel.hybrid_type_name
>> >> <sqlalchemy.orm.attributes.create_proxied_attribute.<locals>.Proxy
>> >> object at 0x7f95594ca200>
>> >>
>> >>
>> >> that's not right.   I see there's a @comparator and also an
>> >> @expression.   Those actually aren't designed to be used together,
>> >> you'd use one or the other.     I'm not sure what you're trying to do
>> >> but based on the organization of what I see you'd want to do this:
>> >>
>> >>     @classmethod
>> >>     def hybrid_type_name_subquery(cls):
>> >>         return select([HybridType.name]).where(HybridType.id ==
>> >> cls.hybrid_type_id).as_scalar()
>> >>
>> >>     class HybridComparator(Comparator):
>> >>
>> >>         def __clause_element__(self):
>> >>             return self.expression.hybrid_type_name_subquery()
>> >>
>> >>         def operate(self, op, other):
>> >>             return op(HybridType.id,
>> >> select([HybridType.id]).where(HybridType.name == other).as_scalar())
>> >>
>> >>     @hybrid_type_name.comparator
>> >>     def hybrid_type_name(cls):
>> >>         return cls.HybridComparator(cls)
>> >>
>> >>
>> >> which gives you a query:
>> >>
>> >>
>> >> print(session.query(HybridModel).order_by(HybridModel.hybrid_type_name))
>> >>
>> >> SELECT hybrids.id AS hybrids_id, hybrids.name AS hybrids_name,
>> >> hybrids.hybrid_type_id AS hybrids_hybrid_type_id, (SELECT
>> >> hybrid_types.name
>> >> FROM hybrid_types
>> >> WHERE hybrid_types.id = hybrids.hybrid_type_id) AS _sa_polymorphic_on
>> >> FROM hybrids ORDER BY (SELECT hybrid_types.name
>> >> FROM hybrid_types
>> >> WHERE hybrid_types.id = hybrids.hybrid_type_id)
>> >>
>> >>
>> >>
>> >>
>> >>
>> >> >
>> >> > 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.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
>> >> >
>> >> >
>> >> > e = create_engine("sqlite://", echo=False)
>> >> > Base.metadata.create_all(e)
>> >> > session = Session(e)
>> >> >
>> >> >
>> >> > session.add(HybridType(name=HybridAlpha.hybrid_type_identity))
>> >> > session.add(HybridType(name=HybridBeta.hybrid_type_identity))
>> >> > session.add(HybridAlpha(name='alpha_instance'))
>> >> > session.add(HybridBeta(name='beta_instance'))
>> >> >
>> >> >
>> >> > print("--- Test query from base hybrid model ---")
>> >> > assert session.query(HybridModel).count() == 2
>> >> > print("passed")
>> >> > print("--- Test query from base derived hybrid model ---")
>> >> > assert session.query(HybridAlpha).count() == 1
>> >> > assert session.query(HybridBeta).count() == 1
>> >> > print("passed")
>> >> > print("--- Test query order_by on hybrid attribute ---")
>> >> > assert [
>> >> >     x.hybrid_type_name for x
>> >> >     in
>> >> > session.query(HybridModel).order_by(HybridModel.hybrid_type_name)
>> >> > ] == [HybridAlpha.hybrid_type_identity,
>> >> > HybridBeta.hybrid_type_identity]
>> >> > print("passed")
>> >> > print("--- Test query filter_by on hybrid attribute ---")
>> >> > assert
>> >> >
>> >> >
>> >> > session.query(HybridModel).filter_by(hybrid_type_name=HybridAlpha.hybrid_type_identity).count()
>> >> > == 1
>> >> > print("passed")
>> >> > print("--- Test query filtered on hybrid attribute ---")
>> >> > assert session.query(HybridModel).filter(HybridAlpha.hybrid_type_name
>> >> > ==
>> >> > HybridAlpha.hybrid_type_identity).count() == 1
>> >> > print("passed")
>> >> >
>> >> >
>> >> >
>> >> > Running this results in the following out put:
>> >> > $ python demo.py
>> >> > --- Test query from base hybrid model ---
>> >> > passed
>> >> > --- Test query from base derived hybrid model ---
>> >> > passed
>> >> > --- Test query order_by on hybrid attribute ---
>> >> > Traceback (most recent call last):
>> >> >   File "demo.py", line 121, in <module>
>> >> >     in
>> >> > session.query(HybridModel).order_by(HybridModel.hybrid_type_name)
>> >> >   File "<string>", line 2, in order_by
>> >> >   File
>> >> >
>> >> >
>> >> > "/Users/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/base.py",
>> >> > line 201, in generate
>> >> >     fn(self, *args[1:], **kw)
>> >> >   File
>> >> >
>> >> >
>> >> > "/Users/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> >> > line 1589, in order_by
>> >> >     criterion = self._adapt_col_list(criterion)
>> >> >   File
>> >> >
>> >> >
>> >> > "/Users/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> >> > line 256, in _adapt_col_list
>> >> >     for o in cols
>> >> >   File
>> >> >
>> >> >
>> >> > "/Users/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/orm/query.py",
>> >> > line 256, in <listcomp>
>> >> >     for o in cols
>> >> >   File
>> >> >
>> >> >
>> >> > "/Users/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/elements.py",
>> >> > line 4191, in _literal_as_label_reference
>> >> >     return _literal_as_text(element)
>> >> >   File
>> >> >
>> >> >
>> >> > "/Users/tbeck/.virtualenvs/cem/lib/python3.5/site-packages/sqlalchemy/sql/elements.py",
>> >> > line 4230, in _literal_as_text
>> >> >     "instead" % type(element)
>> >> > sqlalchemy.exc.ArgumentError: SQL expression object or string
>> >> > expected,
>> >> > got
>> >> > object of type <class
>> >> > 'sqlalchemy.ext.declarative.api.DeclarativeMeta'>
>> >> > instead
>> >> >
>> >> > --
>> >> > 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.
>> >>
>> >> --
>> >> 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 a topic in the
>> >> Google Groups "sqlalchemy" group.
>> >> To unsubscribe from this topic, visit
>> >> https://groups.google.com/d/topic/sqlalchemy/M4b5y_d69u0/unsubscribe.
>> >> To unsubscribe from this group and all its topics, 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.
>> >
>> >
>> >
>> >
>> > --
>> > -=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.
>> > 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.
>>
>> --
>> 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 a topic in the
>> Google Groups "sqlalchemy" group.
>> To unsubscribe from this topic, visit
>> https://groups.google.com/d/topic/sqlalchemy/M4b5y_d69u0/unsubscribe.
>> To unsubscribe from this group and all its topics, 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.
>
>
>
>
> --
> -=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.
> 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.

-- 
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