Awesome!
I like the second approach better for the exact same reasons.
Thanks so much!
Kent
On Thursday, April 13, 2017 at 1:50:40 PM UTC-4, Mike Bayer wrote:
>
>
> it has nothing to do with joined table inheritance, in your example,
> your base mapper is already mapped to "preferences_union", so if you
> provide an alternative selectable that has no relationship to that, it
> does not see any of the required columns being provided. it's just
> like if your PreferencesBase were mapped to a view in the database, it
> would have no idea about the tables represented in that view. so while
> it renders your new polymorphic union, it also renders the old one
> because it still needs to load from preferences_union.c.preferenceid,
> preferences_union.c.value, etc. which are not being substituted.
>
> there's not a facility right now that can automatically handle the
> scenario of, given:
>
>
> SELECT a, b, c FROM (
> select a, b, c FROM table1
> UNION
> select a, b, c FROM table2
> ) AS p_alias_1
>
> that we want to make a whole new expression out of table1/table2:
>
>
> SELECT a, b, c FROM (
> select a, b, c FROM table1 WHERE b=1
> UNION
> select a, b, c FROM table2 WHERE c=2
> ) AS p_alias_2
>
>
> and then "collide" the second into the first, such that we can figure
> out that when our mapping wants p_alias_1.a, it can get that now from
> p_alias_2.a, because this requires understanding the semantics of the
> query. clause adaptation usually looks for the target columns you're
> trying to adapt from in the target selectable, rather than trying to
> match on a general "seems to link to the same common columns" as that
> produces a lot of ambiguous cases.
>
> *unless*, you adapt on the string name of the outer columns rather than
> trying to link them up semantically. In this case, you as the user are
> telling the system that you've already done the work of ensuring your
> new selectable links to the first one the way you want, and you've lined
> up the outermost column names as the means of doing this.
>
> There is an "adapt_on_names" feature that does this, which is provided
> as part of aliased(), where it matches p_alias_1.a to p_alias_2.a using
> the string name "a". adapt_on_names is accepted by aliased(), but
> currently not with_polymorphic() (this can be added, send a PR). So we
> can build up w/ the AliasedClass directly:
>
> from sqlalchemy.orm.util import AliasedClass
>
> a = AliasedClass(
> PreferenceBase,
> u,
> with_polymorphic_mappers=[
> inspect(GlobalPreference),
> inspect(SitePreference),
> inspect(UserPreference)
> ],
> with_polymorphic_discriminator=u.c.type,
> adapt_on_names=True
> )
>
> so that's one way.
>
> next approach, which I think is neater, is to do sort of what I
> suggested but do it by adapting your original polymorphic, so that it
> *does* line up. In the view metaphor, this means you're using the view
> but swapping out the insides. this looks like this:
>
> def apply_polymorphic_criteria(orig, target_table, criteria):
> from sqlalchemy.sql import visitors
>
> def provide_new_select(element):
> if target_table in element.froms:
> element.append_whereclause(criteria)
>
> return visitors.cloned_traverse(
> orig,
> {},
> {"select": provide_new_select}
> )
>
> u = apply_polymorphic_criteria(
> preferences_union,
> userpreferences_table,
> userpreferences_table.c.username == 'kb'
> )
> u = apply_polymorphic_criteria(
> u,
> sitepreferences_table,
> sitepreferences_table.c.siteid == '00'
> )
> a = with_polymorphic(PreferenceBase, '*', selectable=u,
> polymorphic_on=u.c.type)
>
>
> why I like that is because you don't have to build up the whole
> polymorphic_union all over again. also the reliance on names (which
> always makes me nervous) is not needed. I like that approach a lot
> better but there's a little more rocket science involved.
>
> also, I can't rememeber the last time I gave someone a neat little
> recipe to do something unusual and it immediately fails in four other
> ways and then I just have to write them a new feature, so, there's that,
> try out both of these.
>
>
>
>
>
>
>
>
>
> On 04/13/2017 12:39 PM, Kent wrote:
> > That was the first route I tried. with_polymorphic() seems to cater to
> > or assume joined table inheritance. When I pass a selectable, it always
> > ends up *joining *my base to that selectable instead of /using only my
> > selectable/.
> >
> > My problem might be that I'm trying to take advantage of
> > polymorphic_union() to render my union with all the CAST(NULL AS ...),
> > but it does exactly what I need for building a select on the fly.
> >
> > Attached script is my failing attempt.
> >
> > Is there a recipe or example using concrete inheritance and
> > with_polymorphic?
> >
> >
> > On Thursday, April 13, 2017 at 10:43:15 AM UTC-4, Mike Bayer wrote:
> >
> >
> >
> > On 04/13/2017 10:24 AM, Kent wrote:
> > > Suppose we have the documentation's example of *Concrete Table
> > > Inheritance, *where
> > >
> > > session.query(Employee).all()
> > >
> > >
> > > produces this:
> > >
> > > SELECT pjoin.type AS pjoin_type,
> > > pjoin.manager_data AS pjoin_manager_data,
> > > pjoin.employee_id AS pjoin_employee_id,
> > > pjoin.name <http://pjoin.name> AS pjoin_name, pjoin.engineer_info
> > AS pjoin_engineer_info
> > > FROM (
> > > SELECT employees.employee_id AS employee_id,
> > > CAST(NULL AS VARCHAR(50)) AS manager_data, employees.name
> > <http://employees.name> AS name,
> > > CAST(NULL AS VARCHAR(50)) AS engineer_info, 'employee' AS
> > type
> > > FROM employees
> > > UNION ALL
> > > SELECT managers.employee_id AS employee_id,
> > > managers.manager_data AS manager_data, managers.name
> > <http://managers.name> AS name,
> > > CAST(NULL AS VARCHAR(50)) AS engineer_info, 'manager' AS
> type
> > > FROM managers
> > > UNION ALL
> > > SELECT engineers.employee_id AS employee_id,
> > > CAST(NULL AS VARCHAR(50)) AS manager_data, engineers.name
> > <http://engineers.name> AS name,
> > > engineers.engineer_info AS engineer_info, 'engineer' AS type
> > > FROM engineers
> > > ) AS pjoin
> > >
> > >
> > > Suppose we want to*filter certain managers*, which we can do with:
> > >
> > > session.query(Employee)\
> > >
> > > .filter(or_(
> > >
> > > Employee.manager_data == u'whatineed',
> > >
> > > Employee.manager_data == None))\
> > >
> > > .all()
> > >
> > >
> > > If manager_data is indexed, many databases can no longer use this
> > index.
> > > What we really want is:
> > >
> > > SELECT pjoin.type AS pjoin_type,
> > > pjoin.manager_data AS pjoin_manager_data,
> > > pjoin.employee_id AS pjoin_employee_id,
> > > pjoin.name <http://pjoin.name> AS pjoin_name, pjoin.engineer_info
> > AS pjoin_engineer_info
> > > FROM (
> > > SELECT employees.employee_id AS employee_id,
> > > CAST(NULL AS VARCHAR(50)) AS manager_data, employees.name
> > <http://employees.name> AS name,
> > > CAST(NULL AS VARCHAR(50)) AS engineer_info, 'employee' AS
> > type
> > > FROM employees
> > > UNION ALL
> > > SELECT managers.employee_id AS employee_id,
> > > managers.manager_data AS manager_data, managers.name
> > <http://managers.name> AS name,
> > > CAST(NULL AS VARCHAR(50)) AS engineer_info, 'manager' AS
> type
> > > FROM managers
> > >
> > > *WHERE manager_data = 'whatineed'*
> > > UNION ALL
> > > SELECT engineers.employee_id AS employee_id,
> > > CAST(NULL AS VARCHAR(50)) AS manager_data, engineers.name
> > <http://engineers.name> AS name,
> > > engineers.engineer_info AS engineer_info, 'engineer' AS type
> > > FROM engineers
> > > ) AS pjoin
> > >
> > >
> > > Is there a way to accomplish this?
> >
> >
> > Certainly, construct the complete UNION query that you want, most
> > likely
> > using Core select() and union(), and supply it to Query using
> > with_polymorphic; see the "custom selectable" example in
> >
> http://docs.sqlalchemy.org/en/latest/orm/inheritance.html#basic-control-of-which-tables-are-queried
>
> > <
> http://docs.sqlalchemy.org/en/latest/orm/inheritance.html#basic-control-of-which-tables-are-queried>.
>
>
> >
> >
> > Automating this process, perhaps you could compose some enhanced
> > version
> > of the polymorhic_union() feature that accepts additional criteria.
> >
> > However, I would suggest that if the "manager_data is NULL" part is
> > what
> > screws up the index, you might want to query like this instead:
> >
> > session.query(Employee)\
> > .filter(or_(Employee.manager_data == u'whatineed',
> > pjoin.c.type != 'manager')).all()
> >
> >
> > >
> > > Thanks in advance,
> > > Kent
> > >
> > > --
> > > 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> 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 [email protected] <javascript:>
> > > <mailto:[email protected] <javascript:>
> <javascript:>>.
> > > To post to this group, send email to [email protected]
> > <javascript:>
> > > <mailto:[email protected] <javascript:>>.
> > > Visit this group at 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>.
> >
> > --
> > 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 [email protected] <javascript:>
> > <mailto:[email protected] <javascript:>>.
> > To post to this group, send email to [email protected]
> <javascript:>
> > <mailto:[email protected] <javascript:>>.
> > 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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.