SQLAlchemy: Single Table Inheritance, same column in childs
Asked Answered
P

1

7

Im currently mapping a class hierarchy using the single table inheritance strategy (it is not possible for me to use joined). This hierarchy might look like this:

class Parent(Base):
    __tablename__ = 'mytable'
    __mapper_args__ = {
        'polymorphic_on' : type,
        'polymorphic_identity' : 'parent'
    }

    id = Column(Integer, primary_key = True)
    type = Column(String(32), nullable = False)

class Child1(Parent):
    __mapper_args__ = { 'polymorphic_identity' : 'child1' }

    property1 = Column(Integer)

class Child2(Parent):
    __mapper_args__ = { 'polymorphic_identity' : 'child2' }

    property1 = Column(Integer)

class Child3(Parent):
    __mapper_args__ = { 'polymorphic_identity' : 'child3' }

    other_property = Column(Integer)

Well the problem is that I want to have a property1 on both Child1 and Child2 but not on Child3. The current code above results in an error:

sqlalchemy.exc.ArgumentError: Column 'property1' on class <class
'__main__.Child2'>  conflicts with existing column 'mytable.property1'

I could of course add another layer to the inheritance hierarchy which Child1 and Child2 derive from and contains the property1 column, but Child1 and Child2 are hardly related to each other, though I want to reuse the same database column for both classes.

I already tried to add property1 = Child1.property1 to Child2 but that didnt worked (the instance values were not stored in the database for Child2)

Can anyone point out how to reuse a column already defined by another child class?

Polychrome answered 14/6, 2013 at 15:0 Comment(0)
O
15

Adapting directly from the documentation at Resolving Column Conflicts:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base, declared_attr

Base = declarative_base()

class Parent(Base):
    __tablename__ = 'mytable'

    id = Column(Integer, primary_key = True)
    type = Column(String(32), nullable = False)
    __mapper_args__ = {
        'polymorphic_on' : type,
        'polymorphic_identity' : 'parent'
    }

class Child1(Parent):
    __mapper_args__ = { 'polymorphic_identity' : 'child1' }

    @declared_attr
    def property1(cls):
        return Parent.__table__.c.get('property1', Column(Integer))

class Child2(Parent):
    __mapper_args__ = { 'polymorphic_identity' : 'child2' }

    @declared_attr
    def property1(cls):
        return Parent.__table__.c.get('property1', Column(Integer))

class Child3(Parent):
    __mapper_args__ = { 'polymorphic_identity' : 'child3' }

    other_property = Column(Integer)

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)
s.add_all([Child1(property1=1), Child2(property1=2), Child3(other_property=3)])
s.commit()

for p in s.query(Parent):
    if isinstance(p, (Child1, Child2)):
        print p.property1
    elif isinstance(p, Child3):
        print p.other_property
Oxidase answered 17/6, 2013 at 5:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.