> > > mmm what do you mean by "mixin" here, it looks like every class you > have is mapped. > > They are mapped in the code, but that's only so I can query them. I attempted to make LdapEntry and ActiveDirectoryEntry true mixin's by setting __abstract__ = True.
> > this a heavy set of inheritance and I might also use composition > instead, though that would change your DB design. > > The design isn't in production yet so now would be the time to change it. Are you aware of any SQLAlchemy projects using composition I could review? Thanks, Derek On Monday, April 30, 2018 at 1:30:51 PM UTC-5, Mike Bayer wrote: > On Mon, Apr 30, 2018 at 1:33 PM, Derek Lambert > <dlam...@dereklambert.com <javascript:>> wrote: > > I'm running into an issue in a hierarchy of single-table inheritance > objects > > with multiple inheritance. The objects represent users/groups/etc. from > > various directories and applications. > > > > Retrieving the list of synonyms from an object at the bottom of the > > inheritance tree doesn't return the entire list of synonyms. > > > > When I make some of the "mixin" type objects abstract the synonyms > returned > > are as expected, but I lose the ability to query those objects. > > mmm what do you mean by "mixin" here, it looks like every class you > have is mapped. > > I will say that what you are doing here: > > class LdapUser(DirectoryUser, LdapEntry): > givenName = orm.synonym('first_name') > sn = orm.synonym('last_name') > __mapper_args__ = { > 'polymorphic_identity': 'ldap_user', > } > > where DirectoryUser and LdapEntry are also both mapped, I'm amazed > that even works. That's not at all anything that has ever been > supported or attempted, as each mapper only "inherits" from at most > one mapped class - while declarative supports actual "mixin" classes, > where by "mixin" we mean "non-mapped class", nothing in SQLAlchemy ORM > is expecting multiple inheritance at the mapper level. Above, I > guess it's picking one superclass mapper at random to be "inherits", > an ignoring the other, and that is likely the source of your issue. > Unfortunately I think you have to work out this hierarchy in terms of > single-inhertanace for classes that are actually mapped, which means > adding some non-mapped "mixin" classes that just accommodate for the > extra synonyms, something like: > > class DirectoryEntry(Base): > > class AbstractDirectoryUser(object): > # synonyms > > class DirectoryUser(AbstractDirectoryUser, DirectoryEntry): > > class LdapEntry(DirectoryEntry): > > class LdapUser(AbstractDirectoryUser, LdapEntry): > > this a heavy set of inheritance and I might also use composition > instead, though that would change your DB design. > > > > > > Maybe I'm overlooking a simpler implementation, or simply using > SQLAlchemy > > in a way that wasn't intended? > > > > Here's a simplified subset of the code. In practice any object ending > with > > Entry and the base DirectoryUser and DirectoryGroup wouldn't be created. > > > > import sqlalchemy as sa > > import sqlalchemy.orm as orm > > from sqlalchemy.ext.declarative import declarative_base > > > > > > Base = declarative_base() > > > > > > class DirectoryEntry(Base): > > guid = sa.Column(sa.Integer, primary_key=True) > > _type = sa.Column(sa.String, nullable=False, > index=True) > > distinguished_name = sa.Column(sa.String, index=True) > > name = sa.Column(sa.String, index=True) > > > > __tablename__ = 'directory_entry' > > __mapper_args__ = { > > 'polymorphic_on': _type, > > 'polymorphic_identity': 'directory_entry', > > } > > > > > > class DirectoryUser(DirectoryEntry): > > first_name = sa.Column(sa.String) > > last_name = sa.Column(sa.String) > > email = sa.Column(sa.String) > > username = sa.Column(sa.String) > > > > __mapper_args__ = { > > 'polymorphic_identity': 'directory_user', > > } > > > > > > class LdapEntry(DirectoryEntry): > > cn = orm.synonym('name') > > > > __mapper_args__ = { > > 'polymorphic_identity': 'ldap_entry', > > } > > > > > > class LdapUser(DirectoryUser, LdapEntry): > > givenName = orm.synonym('first_name') > > sn = orm.synonym('last_name') > > > > __mapper_args__ = { > > 'polymorphic_identity': 'ldap_user', > > } > > > > > > class ActiveDirectoryEntry(LdapEntry): > > distinguishedName = orm.synonym('distinguished_name') > > > > __mapper_args__ = { > > 'polymorphic_identity': 'active_directory_entry', > > } > > > > > > class ActiveDirectoryUser(LdapUser, ActiveDirectoryEntry): > > mail = orm.synonym('email') > > sAMAccountName = orm.synonym('username') > > > > __mapper_args__ = { > > 'polymorphic_identity': 'active_directory_user' > > } > > > > > > engine_url = 'postgresql+psycopg2://postgres@localhost/inherit_test' > > engine = sa.create_engine(engine_url, echo=True) > > > > Base.metadata.create_all(engine) > > > > session = orm.sessionmaker(bind=engine)() > > ad_user = ActiveDirectoryUser( > > cn='John Doe', > > sAMAccountName='jdoe', > > distinguishedName='ou=domain', > > givenName='John' > > ) > > > > session.add(ad_user) > > session.commit() > > > > user1 = session.query(DirectoryUser).filter(DirectoryUser.username == > > 'jdoe').one() > > user3 = session.query(LdapUser).filter(LdapUser.username == > 'jdoe').one() > > user2 = > > session.query(ActiveDirectoryUser).filter(ActiveDirectoryUser.username > == > > 'jdoe').one() > > user4 = session.query(DirectoryEntry).filter(DirectoryEntry.name == > 'John > > Doe').one() > > > > assert(user1 == user2 == user3 == user4) > > > > mapper = sa.inspect(ad_user.__class__) > > synonyms = mapper.synonyms.keys() > > > > assert(synonyms == ['mail', 'sAMAccountName', 'givenName', 'sn', 'cn', > > 'distinguishedName']) > > > > > > Any help is appreciated! > > > > -- > > 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 <javascript:>. > > To post to this group, send email to sqlal...@googlegroups.com > <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 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.