from sqlalchemy import *
engine = create_engine('sqlite://')
meta = BoundMetaData(engine)

# Parents table.
parents = Table('parents', meta,
	Column("id", Integer, primary_key=True),
	Column("data", String(50), nullable=False)
	)

# Children_1 Table.
children_1 = Table('children_1', meta,
	Column("id", Integer, primary_key=True),
	Column("data", String(50), nullable=False)
	)

# Children_2 Table.
children_2 = Table('children_2', meta,
	Column("id", Integer, primary_key=True),
	Column("data", String(50), nullable=False)
	)

# Association Table.
# This is a generic table which can relate anything to parent.
assoc = Table('assoc', meta,
	# parents.c.id
	Column("parent_id", Integer, ForeignKey(parents.c.id)),
	# associate's id either children_1.c.id or children_2.c.id or any other child.
	Column("assoc_id", Integer, primary_key=True),
	# Which can be either 'child_1' or 'child_2' for now (can be used for extending children
	# type, decides which table to look in.
	Column("assoc_type", String(20), primary_key=True)
	)

class Parent(object):
	def __init__(self, data):
		self.data = data

class Child1(object):
	def __init__(self, data):
		self.data = data

class Child2(object):
	def __init__(self, data):
		self.data = data

class Assoc(object):
	def __init__(self, child_type):
		self.assoc_type = child_type

mapper(Assoc, assoc, properties={
	'parent':relation(Parent, backref=backref('child_associations', uselist=True, cascade="all, delete-orphan"), uselist=False),
	})

mapper(Parent, parents)

def attach_to_parent(cls, cls_type):
	mapper = class_mapper(cls)
	table = mapper.local_table

	primaryjoin=and_(list(table.primary_key)[0]==assoc.c.assoc_id,
			assoc.c.assoc_type==cls_type)
	foreign_keys = [assoc.c.assoc_id,]

	mapper.add_property('parent_assoc', relation(Assoc, primaryjoin=primaryjoin,
		foreign_keys=foreign_keys,
		backref=backref('_backref_%s' % cls_type, primaryjoin=primaryjoin,
			foreign_keys=foreign_keys,
			uselist=False
			),
		cascade="all, delete-orphan"
		))
	def creator(self, **kwds):
		cls_instance = cls(**kwds)
		assoc = Assoc(cls_type)
		assoc.parent = self
		setattr(assoc, '_backref_%s' % cls_type, cls_instance)
		return cls_instance

	setattr(Parent, 'create_%s' % cls.__name__.lower(), creator)

mapper(Child1, children_1)

mapper(Child2, children_2)

attach_to_parent(Child1, 'child_1')
attach_to_parent(Child2, 'child_2')

meta.create_all()

session = create_session(bind_to=engine)

# Let's use it.

my_parent = Parent('Root Parent')
my_child1 = my_parent.create_child1(data='First Child')
my_child2 = my_parent.create_child2(data='Second Child')

session.save(my_parent)
session.flush()
session.clear()

my_parent = session.query(Parent).get(1)
my_child1 = session.query(Child1).get(1)
my_child2 = session.query(Child2).get(1)

assert len(my_parent.child_associations) == 2

session.delete(my_child1)
session.flush()
session.clear()

my_parent = session.query(Parent).get(1)

assert len(my_parent.child_associations) == 1

