Single table inheritance in Camelot
Recently, while working on a class project, I had a small problem with inheritance in Camelot, an excellent framework for rapid application development in Python.
In the application we needed to be able to define different kinds of projects, with similar needs, but which were each available only to some user groups. Single table inheritance sounds like a natural fit for this.
I couldn't find anything in the Camelot documentation about this, but I figured that since it uses SQLAlchemy for its models, I could try the example given there:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(50))
engineer_info = Column(String(50))
type = Column(String(20))
__mapper_args__ = {
'polymorphic_on':type,
'polymorphic_identity':'employee'
}
class Manager(Employee):
__mapper_args__ = {
'polymorphic_identity':'manager'
}
class Engineer(Employee):
__mapper_args__ = {
'polymorphic_identity':'engineer'
}
All is nice and well, except it won't work in Camelot, if we are using the Entity instead of Base, because it gives the following error:
sqlalchemy.exc.ArgumentError: Can't find any foreign key relationships between 'employee' and 'engineer'.
Googling for this wasn't too helpful (and this is why I'm writing this post), so I asked on StackOverflow and on the Camelot mailing list and finally got an answer from Erik, the developer of Camelot.
He said that if Camelot doesn't see tablename defined, it tries to deduce it automatically (and creates something like "engineer"), and then of course, SQLAlchemy thinks it has a multitable inheritance, but doesn't have a foreign key to connect the two tables. So the solution is simple: add tablename = None to each inherited table.
class Manager(Employee):
__tablename__ = None
__mapper_args__ = {
'polymorphic_identity':'manager'
}
class Engineer(Employee):
__tablename__ = None
__mapper_args__ = {
'polymorphic_identity':'engineer'
}
Voila. Hope it helps.