Here's a workaround that tries to adjust for AbstractConcreteBase. The issue is
that ABC does not actually create a "with_polymorphic" selectable that includes
subclass columns, it maps the base class directly to the full selectable so all
those extra columns get mapped. This can probably be improved, and this issue
shouldn't be present with the ConcreteBase class. By limiting the properties on
the local mapper and setting a separate selectable for the load, both issues
are solved, however I haven't tested this robustly. If it works very well for
you we can make this a new feature of ABC, however there would need to be logic
to figure out the correct "include_properties":
class EventDetail(Base, AbstractConcreteBase):
uid = Column(Integer, primary_key=True)
@declared_attr
def event_id(cls):
return Column(Integer, ForeignKey(Event.uid))
@declared_attr
def event(cls):
return relationship(Event, back_populates="details")
__mapper_args__ = {
"include_properties": ["uid", "event_id", "type"],
}
@classmethod
def __declare_last__(cls):
cls.__mapper__.with_polymorphic = ("*", cls.__mapper__.local_table)
On Tue, Mar 3, 2020, at 4:38 PM, Mike Bayer wrote:
>
> The attributes aren't available from the class that they aren't a part of:
>
> (Pdb) ld = LocationDetail()
> (Pdb) hasattr(ld, "starts_at")
> False
> (Pdb) ld.starts_at
> *** AttributeError: Concrete mapped class LocationDetail->LocationDetail does
> not implement attribute 'starts_at' at the instance level. Add this property
> explicitly to mapped class LocationDetail->LocationDetail.
>
> the fact that the attributes are there at all is an artifact of the way
> AbstractConcreteBase works.
>
> There is a way to exclude these properties from the base, which is to use the
> include_properties collection:
>
> class EventDetail(Base, AbstractConcreteBase):
>
> uid = Column(Integer, primary_key=True)
>
> @declared_attr
> def event_id(cls):
> return Column(Integer, ForeignKey(Event.uid))
>
> @declared_attr
> def event(cls):
> return relationship(Event, back_populates="details")
>
> __mapper_args__ = {
> "include_properties": ["uid", "event_id", "type"]
> }
>
> However, this means that the querying the base EventDetail doesn't actually
> *load* those properties; when you access them, an additional SQL query has to
> be emitted. Even worse, they are actually in the original SELECT query but
> they aren't assigned to the objects. I don't know why this is, as the more
> well-maintained forms of inheritance (joined and single) don't have any of
> these issues. These can all be considered to be bugs with concrete
> inheritance but I don't have any solution for them right now.
>
> (also make sure you set up back_populates on your mutually-dependent
> relationships)
>
> Since concrete inheritance is documented as being very buggy (see dragon at
> https://docs.sqlalchemy.org/en/13/orm/inheritance.html#concrete-inheritance)
> I would probably just make EventDetail into a non-mapped mixin class and then
> have LocationDetail and SchedulingDetail load from separate relationships.
>
>
>
>
>
>
>
> On Tue, Mar 3, 2020, at 3:14 PM, Isaac Martin wrote:
>> SQLalchemy prescribes a pattern for dealing with polymorphic relationships
>> which are one to many. You can see this pattern here:
>> https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/api.html#sqlalchemy.ext.declarative.AbstractConcreteBase
>>
>> After implementing this pattern I was pleased to find that it correctly
>> created my tables for the child classes, did not create a table for the
>> parent class, and successfully loads all children into a single collection
>> on the one side of the one to many. Basically everything I wanted.
>>
>> Unfortunately, I quickly came to discover that all child classes had all the
>> fields of all the other child classes. This doesn't happen on the tables, it
>> is only present on the ORM objects after they are loaded. This presents an
>> incredibly poor user experience for the developer. When they inspect these
>> objects they discover a litany of irrelevant fields. Further, tools which
>> visualize the data structure include these fields, making the visualization
>> extremely confusing. For more in depth explanation of my specific
>> implementation you can refer to the stack overflow post:
>> https://stackoverflow.com/questions/60469773/sqlalchemy-polymorphic-pattern-creates-duplicated-columns
>>
>> Does anyone know how to prevent SQL alchemy from including fields from
>> sister objects when implementing this pattern?
>>
>>
>>
>> --
>> 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 view this discussion on the web visit
>> https://groups.google.com/d/msgid/sqlalchemy/7a740ba1-ade8-40fc-914e-85c390e370a8%40googlegroups.com
>>
>> <https://groups.google.com/d/msgid/sqlalchemy/7a740ba1-ade8-40fc-914e-85c390e370a8%40googlegroups.com?utm_medium=email&utm_source=footer>.
>
>
> --
> 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 view this discussion on the web visit
> https://groups.google.com/d/msgid/sqlalchemy/5707a8c9-815e-4cd1-aa73-66eaba2a6245%40www.fastmail.com
>
> <https://groups.google.com/d/msgid/sqlalchemy/5707a8c9-815e-4cd1-aa73-66eaba2a6245%40www.fastmail.com?utm_medium=email&utm_source=footer>.
--
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 view this discussion on the web visit
https://groups.google.com/d/msgid/sqlalchemy/ea6f6069-f640-481f-9f1b-c2fe3684f3b1%40www.fastmail.com.