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/-/qNSg1VvOrWwJ.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to 
> [email protected].
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.







--
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/-/qNSg1VvOrWwJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to [email protected].
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.

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

Base = declarative_base()

class Equipment(Base):
    __tablename__ = 'equipment'
    type = Column(CHAR(1), primary_key=True)
    sub_type = Column(CHAR(1), primary_key=True)
    code = Column(CHAR(5), primary_key=True)

    _concat_type_col = type + "|" + sub_type
    concat_type = column_property(_concat_type_col)

    @declared_attr
    def __mapper_args__(cls):
        # note that the "polymorphic_on" argument must be 
        # explicit with all subclass mappers as well, as currently
        # a column_property()-based polymorphic_on is not propagated
        # to single-table inh subclasses.  An interim patch 
        # in ticket #2227 fixes this but ticket #2238 seeks to 
        # address this more generally
        return {
            'polymorphic_on': cls._concat_type_col, 
            'polymorphic_identity' : cls.cls_type + "|" + cls.cls_sub_type}
    cls_type = 'equip'
    cls_sub_type = ''

    def __init__(self, code):
        self.type = self.cls_type
        self.sub_type = self.cls_sub_type
        self.code = code

class Vehicle(Equipment):
    cls_sub_type = 'V'

class Bus(Vehicle):
    cls_sub_type = 'B'

class Rail(Vehicle):
    cls_sub_type = 'R'

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

s = Session(e)

s.add_all([
    Bus(code='bus'),
    Rail(code='rail'),
    Vehicle(code='veh'),
    Equipment(code='equip')
])
s.commit()

assert set(e.__class__ for e in s.query(Vehicle)) == set([Vehicle, Bus, Rail])
assert set(e.__class__ for e in s.query(Equipment)) == set([Equipment, Vehicle, Bus, Rail])
assert set(e.__class__ for e in s.query(Rail)) == set([Rail])

Reply via email to