Skip to content

Instantly share code, notes, and snippets.

@storborg
Created January 27, 2011 01:28
Show Gist options
  • Save storborg/797893 to your computer and use it in GitHub Desktop.
Save storborg/797893 to your computer and use it in GitHub Desktop.
$ python polymorphic_trick.py
2011-01-26 17:28:06,918 INFO sqlalchemy.engine.base.Engine.0x...5a90 PRAGMA table_info("employees")
2011-01-26 17:28:06,918 INFO sqlalchemy.engine.base.Engine.0x...5a90 ()
2011-01-26 17:28:06,919 INFO sqlalchemy.engine.base.Engine.0x...5a90 PRAGMA table_info("developers")
2011-01-26 17:28:06,919 INFO sqlalchemy.engine.base.Engine.0x...5a90 ()
2011-01-26 17:28:06,919 INFO sqlalchemy.engine.base.Engine.0x...5a90
CREATE TABLE employees (
id INTEGER NOT NULL,
name VARCHAR(50),
discriminator VARCHAR(50),
PRIMARY KEY (id)
)
2011-01-26 17:28:06,919 INFO sqlalchemy.engine.base.Engine.0x...5a90 ()
2011-01-26 17:28:06,919 INFO sqlalchemy.engine.base.Engine.0x...5a90 COMMIT
2011-01-26 17:28:06,920 INFO sqlalchemy.engine.base.Engine.0x...5a90
CREATE TABLE developers (
employee_id INTEGER NOT NULL,
language VARCHAR(50),
editor VARCHAR(50),
PRIMARY KEY (employee_id),
FOREIGN KEY(employee_id) REFERENCES employees (id)
)
2011-01-26 17:28:06,920 INFO sqlalchemy.engine.base.Engine.0x...5a90 ()
2011-01-26 17:28:06,921 INFO sqlalchemy.engine.base.Engine.0x...5a90 COMMIT
2011-01-26 17:28:06,923 INFO sqlalchemy.engine.base.Engine.0x...5a90 BEGIN (implicit)
2011-01-26 17:28:06,924 INFO sqlalchemy.engine.base.Engine.0x...5a90 INSERT INTO employees (name, discriminator) VALUES (?, ?)
2011-01-26 17:28:06,924 INFO sqlalchemy.engine.base.Engine.0x...5a90 ('bob', None)
2011-01-26 17:28:06,924 INFO sqlalchemy.engine.base.Engine.0x...5a90 INSERT INTO employees (name, discriminator) VALUES (?, ?)
2011-01-26 17:28:06,924 INFO sqlalchemy.engine.base.Engine.0x...5a90 ('joe', None)
2011-01-26 17:28:06,925 INFO sqlalchemy.engine.base.Engine.0x...5a90 INSERT INTO employees (name, discriminator) VALUES (?, ?)
2011-01-26 17:28:06,925 INFO sqlalchemy.engine.base.Engine.0x...5a90 ('sam', None)
2011-01-26 17:28:06,926 INFO sqlalchemy.engine.base.Engine.0x...5a90 INSERT INTO developers (employee_id, language, editor) VALUES (?, ?, ?)
2011-01-26 17:28:06,926 INFO sqlalchemy.engine.base.Engine.0x...5a90 (2, 'python', 'vim')
2011-01-26 17:28:06,926 INFO sqlalchemy.engine.base.Engine.0x...5a90 INSERT INTO developers (employee_id, language, editor) VALUES (?, ?, ?)
2011-01-26 17:28:06,926 INFO sqlalchemy.engine.base.Engine.0x...5a90 (3, 'python', 'vim')
2011-01-26 17:28:06,926 INFO sqlalchemy.engine.base.Engine.0x...5a90 COMMIT
**** employees ****
2011-01-26 17:28:06,927 INFO sqlalchemy.engine.base.Engine.0x...5a90 BEGIN (implicit)
2011-01-26 17:28:06,928 INFO sqlalchemy.engine.base.Engine.0x...5a90 SELECT employees.id AS employees_id, employees.name AS employees_name, employees.discriminator AS employees_discriminator
FROM employees
2011-01-26 17:28:06,928 INFO sqlalchemy.engine.base.Engine.0x...5a90 ()
[<__main__.Employee object at 0x101510f90>, <__main__.Developer object at 0x101510f50>, <__main__.Hacker object at 0x1015176d0>]
**** hackers ****
2011-01-26 17:28:06,929 INFO sqlalchemy.engine.base.Engine.0x...5a90 SELECT employees.id AS employees_id, employees.name AS employees_name, employees.discriminator AS employees_discriminator, developers.employee_id AS developers_employee_id, developers.language AS developers_language, developers.editor AS developers_editor
FROM employees JOIN developers ON employees.id = developers.employee_id
2011-01-26 17:28:06,929 INFO sqlalchemy.engine.base.Engine.0x...5a90 ()
[<__main__.Developer object at 0x101510f50>, <__main__.Hacker object at 0x1015176d0>]
from sqlalchemy import MetaData, Column, ForeignKey, types, create_engine, orm
from sqlalchemy.ext.declarative import (declarative_base, declared_attr,
has_inherited_table)
engine = create_engine('sqlite://', echo=True)
sm = orm.sessionmaker(bind=engine)
metadata = MetaData()
metadata.bind = engine
Base = declarative_base(metadata=metadata)
class PolymorphicMixin(object):
@declared_attr
def discriminator(cls):
if Base in cls.__bases__:
return Column('discriminator', types.String(50))
for b in cls.__bases__:
if hasattr(b, 'discriminator'):
return b.discriminator
@declared_attr
def __mapper_args__(cls):
ret = {'polymorphic_identity': cls.__name__}
if Base in cls.__bases__:
ret['polymorphic_on'] = PolymorphicMixin.discriminator
return ret
class Employee(Base, PolymorphicMixin):
__tablename__ = 'employees'
id = Column(types.Integer, primary_key=True)
name = Column(types.String(50))
class Developer(Employee):
__tablename__ = 'developers'
employee_id = Column(None, ForeignKey('employees.id'), primary_key=True)
language = Column(types.String(50), default='python')
editor = Column(types.String(50), default='vim')
class Hacker(Developer):
pass
#### use it ####
metadata.create_all()
sess = orm.scoped_session(sm)
emp = Employee(name='bob')
sess.add(emp)
dev = Developer(name='joe')
sess.add(dev)
hacker = Hacker(name='sam')
sess.add(hacker)
sess.commit()
print "**** employees ****"
print sess.query(Employee).all()
print "**** hackers ****"
print sess.query(Hacker).all()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment