Thanks again for the link to the "Polymorphic Associations with
SQLAlchemy" article. You're right, that's the same problem I had been
facing. Your generic solution is not applicable for me, because I can't
change the database design, but the elementary solution is good enough.
For the curious, here is my application to the example I had posted:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Boolean, String
engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()
class CountryNat(Base):
__tablename__ = 'country_nat'
country_id = Column(String(2), primary_key=True)
name = Column(String(40))
def __init__(self, country_id, name):
self.country_id = country_id
self.name = name
class CountryInt(Base):
__tablename__ = 'country_int'
country_id = Column(String(2), primary_key=True)
name = Column(String(40))
def __init__(self, country_id, name):
self.country_id = country_id
self.name = name
class Contact(Base):
__tablename__ = 'contact'
name = Column(String(80), primary_key=True)
native = Column(Boolean())
country_id = Column(String(2))
country_nat = relationship(CountryNat,
primaryjoin=country_id==CountryNat.country_id,
foreign_keys=[country_id])
country_int = relationship(CountryInt,
primaryjoin=country_id==CountryInt.country_id,
foreign_keys=[country_id])
country = property(lambda self: getattr(self,
'country_%s' % ('nat' if self.native else 'int')))
def __init__(self, name, native, country_id):
self.name = name
self.native = native
self.country_id = country_id
Base.metadata.create_all(engine)
if not session.query(Contact).first():
session.add_all([
CountryNat('IL', 'Illinois'),
CountryNat('NY', 'New York'),
CountryInt('KZ', 'Kazakhstan'),
CountryInt('NL', 'Netherlands'),
Contact('Flozell Adams', True, 'IL'),
Contact('Vince Lombardi', True, 'NY'),
Contact('Borat Sagdiyev', False, 'KZ'),
Contact('Ryan Donk', False, 'NL')])
session.commit()
for contact in session.query(Contact):
print "%s, %s" % (
contact.name,
contact.country.name)