On May 16, 2013, at 3:02 PM, Bobby  Impollonia <bob...@gmail.com> wrote:

> 
> I hoped to end up with something like:
> SELECT email_addresses.id AS email_addresses_id, email_addresses.address AS 
> email_addresses_address
> FROM email_addresses, affiliations
> WHERE affiliations.address_type = 'email' AND affiliations.address_id = 
> email_addresses.id AND affiliations.id = 1
> 
> Two questions:
> 1) Is the behavior I am seeing here expected given my relationship 
> configuration?
> 2) How can I configure my relationship to exhibit the desired behavior in the 
> situation shown above?

Ok well lets think of it in terms of joins.  What if you wanted to load all the 
affiliations and EmailAddresses together?  the join would be:

select * from affiliations JOIN email_addresses ON 
affiliations.address_id=email_addresses.id AND affiliations.address_type='email'

above, there's not really a space for "AND affiliations.id = ...something ?", 
unless maybe if it were equated to itself.

So maybe, this kind of thing would be possible if you could say:

    email_address = relationship(
        'EmailAddress',
        primaryjoin=and_(address_type == 'email',
                        id == lazy(id),
                         address_id  == EmailAddress.id),
        foreign_keys=[address_id],
        viewonly=True)

the lazy load would need to figure out to set up a bind for one of the slot 
there (that's the hypothetical "lazy()" annotation).   its funny we're a lot 
closer to that sort of thing, since we do have situations where we have things 
like "column == remote(column)" now, but not quite in that arrangement.

But I don't think we need to get into any of that here since your class has a 
discriminator anyway, we can just use inheritance so that your different 
Affiliation objects know what to do, see below.


#!/usr/bin/env python
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine, and_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, backref, contains_eager, 
remote

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)


class StreetAddress(Base):
    __tablename__ = 'steet_addresses'
    id = Column(Integer, primary_key=True)
    address = Column(String, nullable=False)


class EmailAddress(Base):
    __tablename__ = 'email_addresses'
    id = Column(Integer, primary_key=True)
    address = Column(String, nullable=False)


class Affiliation(Base):
    __tablename__ = 'affiliations'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'), nullable = False)
    address_type = Column(String, nullable=False)
    address_id = Column(Integer, nullable=False)

    user = relationship("User", backref='affiliations')

    street_address = None
    email_address = None

    __mapper_args__ = dict(polymorphic_on=address_type)

class EmailAffiliation(Affiliation):

    email_address = relationship(
        'EmailAddress',
        primaryjoin=Affiliation.address_id  == EmailAddress.id,
        foreign_keys=[Affiliation.address_id],
        viewonly=True)
    __mapper_args__ = dict(polymorphic_identity='email')

class StreetAffiliation(Affiliation):

    street_address = relationship(
        'StreetAddress',
        primaryjoin=Affiliation.address_id == StreetAddress.id,
        foreign_keys=[Affiliation.address_id],
        viewonly=True)
    __mapper_args__ = dict(polymorphic_identity='street')


Base.metadata.create_all(engine)

user = User(id=1)
email = EmailAddress(id=1, address='y...@localhost.com')
street = StreetAddress(id=1, address='123 Main str.')
session.add_all([
    user,
    email,
    street,
])
session.flush()
street_affiliation = StreetAffiliation(user=user, address_id=1)
email_affiliation = EmailAffiliation(user=user, address_id=1)
session.add_all([
    street_affiliation,
    email_affiliation,
])
session.flush()
session.commit()


assert street_affiliation.street_address is not None
assert email_affiliation.email_address is not None
assert street_affiliation.email_address is None
assert email_affiliation.street_address is None


-- 
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 http://groups.google.com/group/sqlalchemy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to