Skip to content

Instantly share code, notes, and snippets.

@dusktreader
Last active December 1, 2016 23:08
Show Gist options
  • Save dusktreader/2658dedb8ca8e2fd941f8075c75b3c89 to your computer and use it in GitHub Desktop.
Save dusktreader/2658dedb8ca8e2fd941f8075c75b3c89 to your computer and use it in GitHub Desktop.
SQLAlchemy single-table inheritance by foreign key hybrid property
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import sessionmaker, relationship, column_property
from sqlalchemy import (
Column, Integer, ForeignKey, Text,
select, create_engine,
)
Base = declarative_base()
class HybridType(Base):
__tablename__ = 'hybrid_types'
id = Column(Integer, primary_key=True)
name = Column(Text)
class HybridModel(Base):
__tablename__ = 'hybrids'
id = Column(Integer, primary_key=True)
name = Column(Text)
hybrid_type_id = Column(Integer, ForeignKey('hybrid_types.id'))
hybrid_type = relationship('HybridType')
@classmethod
def hybrid_type_identity(cls):
return cls.__name__
@declared_attr
def __mapper_args__(cls):
return dict(
polymorphic_on=cls.hybrid_type_name,
polymorphic_identity=cls.hybrid_type_identity(),
)
def __repr__(self):
return "{} ({}:{})".format(self.hybrid_type_identity(), self.name, self.id)
def __init__(self, **kwargs):
self.hybrid_type_name = self.hybrid_type_identity()
super(HybridModel, self).__init__(**kwargs)
@hybrid_property
def hybrid_type_name(self):
return self.hybrid_type.name
@hybrid_type_name.expression
def hybrid_type_name(cls):
return (
select([HybridType.name]).
where(HybridType.id == cls.hybrid_type_id).
as_scalar()
)
@hybrid_type_name.setter
def hybrid_type_name(self, value):
self.hybrid_type_id = (
select([HybridType.id]).
where(HybridType.name == value)
)
class HybridAlpha(HybridModel):
pass
class HybridBeta(HybridModel):
pass
if __name__ == '__main__':
engine = create_engine('sqlite:///:memory:', echo=False)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
for cls in [HybridModel, HybridAlpha, HybridBeta]:
session.add(HybridType(name=cls.hybrid_type_identity()))
session.add(HybridModel(name='base_instance'))
session.add(HybridAlpha(name='alpha_instance'))
session.add(HybridBeta(name='beta_instance1'))
session.add(HybridBeta(name='beta_instance2'))
print("All instances:")
for cls in [HybridModel, HybridAlpha, HybridBeta]:
print(" {} instances: {}".format(cls.hybrid_type_identity(), session.query(cls).all()))
print("Reasssigning alpha instance to beta type")
session.query(HybridAlpha).one().hybrid_type_name = HybridBeta.hybrid_type_identity()
print("All instances:")
for cls in [HybridModel, HybridAlpha, HybridBeta]:
print(" {} instances: {}".format(cls.hybrid_type_identity(), session.query(cls).all()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment