Hi Michael, I have a similar (but subtly different) problem to this, trying to mix single- and joined-table inheritance. Essentially my model looks as follows:
Product(Base) PhysicalProduct(Product) NonPhysicalProduct(Product) The Physical/NonPhysicalProduct use single table inheritance whilst objects inheriting from them use joined tables... I have a fully working model --- and there's no question that it works!! But I can't help feeling that I've missed something relating to the __mapper_args__ which is then requiring explicit calls to __init__ objects higher up the tree. (rather than bunging up this message, please see the attached file) I'd be really grateful if you could take a look and hopefully point me in the right direction. Many thanks, Rob On Wednesday, 17 August 2011 00:42:28 UTC+1, Michael Bayer wrote: > > > On Aug 16, 2011, at 5:37 PM, Mike Gilligan wrote: > > I have a single table that looks similar to the following: > > class Equipment(Base): > type = Column(CHAR(1), primary_key=True) > sub_type = Column(CHAR(1), primary_key=True) > code = Column(CHAR(5), primary_key=True) > > > For historical purposes, I cannot modify this table. I would like to setup > multi-level inheritance similar to this, however it does not work: > > class Equipment(Base): > type = Column(CHAR(1), primary_key=True) > sub_type = Column(CHAR(1), primary_key=True) > code = Column(CHAR(5), primary_key=True) > __mapper_args__ = {'polymorphic_on': type} > > > class Vehicle(Equipment): > __mapper_args__ = {'polymorphic_identity': 'V', 'polymorphic_on': > sub_type} > > > class Bus(Vehicle) > __mapper_args__ = {'polymorphic_identity': 'B'} > > > class Rail(Vehicle) > __mapper_args__ = {'polymorphic_identity': 'R'} > > > I can concatenate the multiple column values into a single discriminator > column_property but then I do not have an easy way to retrieve all > vehicles. Any ideas? > > > The inheritance querying does handle multi-level inheritance so if your > discriminator was on a concatenation of both things would work just fine, > i.e. if you queried for Vehicle, etc. Each object's > "polymorphic_identity" would need to include the concatenated value, of > course. > > Unfortunately we're just beginning to support inheritance discriminators > on a column_property(), and you need to use a very specific approach to > make this work right now. There's some tickets in trac to allow this > functionality out of the box. Attached is an example script which > exercises the above mapping - it uses declarative to minimize the impact of > the workaround. > > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/KzPgMan_6MIJ. To post to this group, send email to sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
""" mixed single and joined table inheritance. """ from sqlalchemy import * from sqlalchemy import types from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base, declared_attr Base = declarative_base() class Product(Base): __tablename__ = 'products' id = Column(types.Integer, primary_key=True) discriminator = Column('product_type', types.String(50), nullable=False) __mapper_args__ = {'polymorphic_on': discriminator} def price_history(self): return [] class PhysicalProduct(Product): p_discr = Column(types.String(50)) @declared_attr def __mapper_args__(cls): return {'polymorphic_on': cls.p_discr, 'polymorphic_identity' : 'physical_product'} def __init__(self, **kw): print "init PP kwargs:", kw self.discriminator = 'physical_product' def inventory(self): return "computed inventory" class NonPhysicalProduct(Product): np_discr = Column(types.String(50)) @declared_attr def __mapper_args__(cls): return {'polymorphic_on': cls.np_discr, 'polymorphic_identity' : 'nonphysical_product'} def __init__(self, **kw): print "init NP kwargs:", kw self.discriminator = 'nonphysical_product' def somefunc(self): return "someval" class Newspaper(PhysicalProduct): __tablename__ = 'newspapers' __mapper_args__ = {'polymorphic_identity': 'newspaper'} id = Column(types.Integer, ForeignKey('products.id'), primary_key=True ) title = Column(types.String(50)) def __init__(self, title): self.title = title super(Newspaper, self).__init__() class NewspaperDelivery(NonPhysicalProduct): __tablename__ = 'deliveries' __mapper_args__ = {'polymorphic_identity': 'delivery'} id = Column(types.Integer, ForeignKey('products.id'), primary_key=True ) destination = Column(types.String(50)) def __init__(self, destination): self.destination = destination super(NewspaperDelivery, self).__init__() e = create_engine('sqlite:///:memory:', echo=True) Base.metadata.drop_all(e) Base.metadata.create_all(e) session = Session(e, autoflush=True, autocommit=False) session.add_all([ Newspaper(title="Financial Times"), NewspaperDelivery(destination="__somewhere__") ]) session.commit()