Okay, thanks a lot. 2017-10-28 13:36 GMT-04:00 Mike Bayer <mike...@zzzcomputing.com>:
> On Fri, Oct 27, 2017 at 9:54 PM, <char...@konversion.ca> wrote: > > I'm not querying polymorphically. > > > > Let me restate the problem with more details(my post as done in haste). > > > > With something like the example I gave(completed with what's missing, > e.g. > > table names, definition for related table), > > thank you, with the stack trace I can construct what is going on. > > There is a bug that needs a patch to work, in terms of the descriptor, > this is up at https://bitbucket.org/zzzeek/sqlalchemy/issues/4124/ > abstractconcretebase-transmitting > and the patch you see here: > https://gerrit.sqlalchemy.org/#/c/590/1/lib/sqlalchemy/orm/loading.py > fixes it. > > Also, your Concrete1 and Concrete2 classes should specify > __mapper_args__ = {"concrete": True}, without that, you can also get > this problem even without the start/end descriptors, but the fix in > 4124 above will also prevent this scenario from occurring. > > However this part: > > > > > MyBase.start, MyBase.end # that's weird, the Abstract base also has those > > attributes now > > that part is normal. The AbstractConcreteBase indicates you'd like > to query across all subclasses at once, and the way it works out at > the moment is that you'll see every column mapped get associated with > it and you do have start/end columns mapped. if you don't need to > query in this way (which in general it's inefficient from a SQL > perspective), you should not use AbstractConcreteBase. Polymorphic > querying across concrete subclasses is a worst case scenario and ACB > is still pretty hacky. > > > > > > > > > session.expire(results[0]) > > results[0].start > > > > Traceback (most recent call last): > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/IPython/core/interactiveshell.py", > > line 3035, in run_code > > exec(code_obj, self.user_global_ns, self.user_ns) > > File "<ipython-input-14-25b20252b355>", line 1, in <module> > > results[0].start > > File "/home/charles/PycharmProjects/MyProject/my_models.py", line > 456, in > > start > > return self.details.start > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/attributes.py", > > line 237, in __get__ > > return self.impl.get(instance_state(instance), dict_) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/attributes.py", > > line 584, in get > > value = self.callable_(state, passive) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/strategies.py", > > line 539, in _load_for_state > > passive > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/strategies.py", > > line 575, in _get_ident_for_use_get > > for pk in self.mapper.primary_key > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/strategies.py", > > line 575, in <listcomp> > > for pk in self.mapper.primary_key > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", > > line 2564, in _get_state_attr_by_column > > return state.manager[prop.key].impl.get(state, dict_, > passive=passive) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/attributes.py", > > line 579, in get > > value = state._load_expired(state, passive) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/state.py", > > line 592, in _load_expired > > self.manager.deferred_scalar_loader(self, toload) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/loading.py", > > line 713, in load_scalar_attributes > > only_load_props=attribute_names) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/loading.py", > > line 223, in load_on_ident > > return q.one() > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/query.py", > > line 2814, in one > > ret = self.one_or_none() > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/query.py", > > line 2784, in one_or_none > > ret = list(self) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/loading.py", > > line 90, in instances > > util.raise_from_cause(err) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/util/compat.py", > > line 203, in raise_from_cause > > reraise(type(exception), exception, tb=exc_tb, cause=cause) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/util/compat.py", > > line 187, in reraise > > raise value > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/loading.py", > > line 57, in instances > > for query_entity in query._entities > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/loading.py", > > line 57, in <listcomp> > > for query_entity in query._entities > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/query.py", > > line 3700, in row_processor > > polymorphic_discriminator=self._polymorphic_discriminator > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/loading.py", > > line 299, in _instance_processor > > mapper._props[k] for k in only_load_props) > > File > > "/home/charles/PycharmProjects/MyProject/env/ > lib/python3.6/site-packages/sqlalchemy/orm/loading.py", > > line 299, in <genexpr> > > mapper._props[k] for k in only_load_props) > > KeyError: 'start' > > > > > > So on refresh, the loading process seems to expect 'start' and 'end' to > be > > registered by the mappers(which they would be if they were columns, I > > guess). > > > > > > Le vendredi 27 octobre 2017 13:36:53 UTC-4, Mike Bayer a écrit : > >> > >> On Fri, Oct 27, 2017 at 11:57 AM, <cha...@konversion.ca> wrote: > >> > My SQLAlchemy version is 1.1.14. > >> > > >> > I'm having difficulty understanding behaviours around a polymorphic > >> > hierarchy. > >> > > >> > I have an AbstractConcreteBase and two subclasses. > >> > > >> > The ACB declares some attributes shared by the two subclasses, and the > >> > subclasses have attributes of their own that are not shared(i.e. they > >> > are > >> > not part of the shared identity represented by the ACB). > >> > > >> > class MyBase(AbstractConcreteBase, Base, Mixin): > >> > shared_id = Column(Integer, > >> > default=Sequence("database_shared_id_seq", > >> > start=0, increment=1), primary_key=True) > >> > > >> > @declared_attr > >> > def name(self): > >> > return Column(String(100), nullable=False) > >> > > >> > @declared_attr > >> > def foreign_key(self): > >> > return Column(Integer, ForeignKey("MyOtherTable.id")) > >> > > >> > ... > >> > > >> > > >> > class Concrete1(MyBase): > >> > start = Column(Date) > >> > end = Column(Date) > >> > > >> > > >> > class Concrete2(MyBase): > >> > > >> > @property > >> > def start(self): > >> > return self.details.start > >> > > >> > @property > >> > def end(self): > >> > return self.details.end > >> > > >> > details = relationship("Concrete2Detail", uselist=False, > >> > viewonly=True) > >> > > >> > > >> > As you can see, "start" and "end" are not declared in the ACB and are > >> > implemented differently between the table. I don't want them to be > >> > shared by > >> > the subclasses. > >> > > >> > When I query one of the Concretes, the ACB mapper is updated with the > >> > "start" and "end" attributes, and then the Concretes are expected to > >> > implement the attributes on the mapper level(which is not the case for > >> > Concrete2). > >> > >> This is a natural effect of using an "abstract" base. When you try > >> to query polymorphically across Concrete1 and Concrete2, you're asking > >> it to query for the Concrete1.start and end columns. However it > >> should not in any way be modifying the Concrete2 mapper itself. I'm > >> not sure without running it what "are expected to implement" means. > >> An error is raised? > >> > >> > >> > > >> > How can I prevent this from happening? > >> > > >> > -- > >> > 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+...@googlegroups.com. > >> > To post to this group, send email to sqlal...@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. > > -- > 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/9uFXrbPMlXI/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. > -- *Charles Langlois* * Programmeur-analyste - Programmer Analyst* 5605 avenue de Gaspé <https://maps.google.com/?q=5605+avenue+de+Gasp%C3%A9&entry=gmail&source=g>, Suite 902 Montréal, QC, Canada - H2T 2A4 -- 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.