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)