Answer Ilja Everilä is already the best option. Although it does not literally save the class_id value inside the table, note that any two instances of the same class always have the same class_id value. Knowing the class is enough to compute class_id for any given element. In the sample code that Ilya provided, the type column ensures that the class is always known, and the class property class_id takes care of the rest. That way, class_id is still displayed in the table, if indirectly.
I repeat the example of Elijah from his original answer here, if he decides to change it in his post. Call it "solution 1".
class Item(Base): name = 'unnamed item' @classproperty def class_id(cls): return '.'.join((cls.__module__, cls.__qualname__)) __tablename__ = 'item' id = Column(Integer, primary_key=True) type = Column(String(50)) __mapper_args__ = { 'polymorphic_identity': 'item', 'polymorphic_on': type } class Sword(Item): name = 'Sword' __tablename__ = 'sword' id = Column(Integer, ForeignKey('item.id'), primary_key=True) durability = Column(Integer, default=100) __mapper_args__ = { 'polymorphic_identity': 'sword', } class Pistol(Item): name = 'Pistol' __tablename__ = 'pistol' id = Column(Integer, ForeignKey('item.id'), primary_key=True) ammo = Column(Integer, default=10) __mapper_args__ = { 'polymorphic_identity': 'pistol', }
Ilya hinted at a solution in his last comment on the question using @declared_attr , which would literally save class_id inside the table, but I think it would be less elegant. Everything that you buy represents the same information in a slightly different way, due to the fact that your code becomes more complex. See for yourself ("solution 2"):
class Item(Base): name = 'unnamed item' @classproperty def class_id_(cls):
There is an additional danger in this approach, which I will discuss below.
In my opinion, it would be more elegant to make the code simpler. This can be achieved starting with solution 1, and then merging the name and type properties, since they are redundant ("solution 3"):
class Item(Base): @classproperty def class_id(cls): return '.'.join((cls.__module__, cls.__qualname__)) __tablename__ = 'item' id = Column(Integer, primary_key=True) name = Column(String(50))
All three solutions discussed so far give you the same requested behavior on the Python side (assuming you ignore the type attribute). For example, a Pistol instance returns 'yourmodule.Pistol' as its class_id and 'Pistol' as its name in each solution. Also in each solution, if you add a new element class to the hierarchy, say Key , all its instances automatically report that their class_id will be 'yourmodule.Key' , and you can set their common name once at the class level.
There are some subtle differences on the SQL side regarding the name and value of a column that ambiguously separates element classes. In solution 1, the column is called type , and its value is arbitrarily selected for each class. In solution 2, the column name is class_id , and its value is equal to the class property, which depends on the class name. In solution 3, the name name and its value are equal to the name property of the class, which can be independently changed from the class name. However, since all of these different ways of eliminating the element class ambiguity can be displayed to each other with each other, they contain the same information.
I already mentioned that there is a problem that solution 2 eliminates the element class ambiguity. Suppose you decide to rename the Pistol class to Gun . Gun.class_id_ (with a final underscore) and Gun.__mapper_args__['polymorphic_identity'] will automatically change to 'yourmodule.Gun' . However, the class_id column in your database (displayed in Gun.class_id without end underscore) will contain 'yourmodule.Pistol' . The database migration tool may not be smart enough to realize that these values need to be updated. If you are not careful, your class_id will be corrupted, and SQLAlchemy will most likely throw exceptions because you cannot find the appropriate classes for your elements.
You could avoid this problem by using an arbitrary value as a disamigrator, as in solution 1, and save the class_id in a separate column using the @declared_attr magic (or a similar indirect route), as in solution 2. However, at this point you really need to ask myself, why class_id should be in the database table. Does this really justify the complexity of your code?
Take the home message : you can map simple class attributes as well as computed class properties using SQLAlchemy, even in the face of inheritance, as shown in the solutions. This does not necessarily mean that you should do it. Start with your ultimate goals and find the easiest way to achieve these goals. Just make your decision more complex if it solves the real problem.