Ok, thank you, that helps, but now i cannot inherit from Engineer, as in:

class BaseMixin(object):

    discriminator = Column(String(50))

    @declared_attr
    def __tablename__(cls):
        return cls.__name__
    @declared_attr
    def id(cls):
        return Column(Integer, primary_key = True)
    @declared_attr
    def __mapper_args__(cls):
        if not has_inherited_table(cls):
            return {'polymorphic_on': 'discriminator'}
        else:
            return {'polymorphic_identity': cls.__name__}


class InheritMixin(BaseMixin):
    @declared_attr
    def id(cls):
        super_id = super(InheritMixin, cls).id
        return Column(Integer, ForeignKey(super_id), primary_key = True)
    
class Person(BaseMixin, Base):
    name = Column(String(50))
   
class Engineer(InheritMixin, Person):
    job = Column(String(50))

class MasterEngineer(InheritMixin, Engineer):
    specialty = Column(String(50))

Gives an MRO() error and if i would reverse the baseclasses (like class 
Engineer(Person, InheritMixin):  ... ), the inheriting classes pick up the 
wrong id.

Do you see any solution for this? 

BTW: could i just move

    @declared_attr
    def __mapper_args__(cls):
        return {'polymorphic_identity': cls.__name__}

to InheritMixin instead of doing the 'has_inherited_table' if-statement in 
BaseMixin?

Cheers, Lars


On Friday, April 20, 2012 12:41:28 PM UTC+2, Michael Bayer wrote:
>
>
> On Apr 20, 2012, at 4:59 AM, lars van gemerden wrote:
>
> > this is the testcase:
> > 
> > 
> > What am i missing?
>
>
> the issue here is one of Python inheritance mechanics.   Declarative calls 
> upon @declared_attr in terms of the class, that is, we look through the 
> class to find each @declared_attr, but when we find one, we invoke it by 
> just calling it as a method, that is, getattr(cls, name).   This works for 
> things like __mapper_args__ which remain as callable methods on classes 
> like Person, Engineer.   But "id", when that is declared on Person is 
> immediately replaced with a mapping.   By the time you get to Engineer, the 
> id() method is gone.
>
> So for inheriting cases you need to build a mixin that is applied to every 
> subclass.  This makes sense because a mixin with a column on it implies 
> that the column is being associated only with that immediate class - if you 
> wanted a subclass to act as single table inheritance, you'd omit this 
> class.  In this case you want the same column on all subclasses.    So you 
> can do it like this (note also using declarative.has_inherited_table 
> helper):
>
> class InheritMixin(object):
>
>    @declared_attr
>    def __tablename__(cls):
>        return cls.__name__
>
>    @declared_attr
>    def id(cls):
>        return Column(Integer, primary_key = True)
>
>    @declared_attr
>    def __mapper_args__(cls):
>        if not has_inherited_table(cls):
>            return {'polymorphic_on': 'discriminator'}
>        else:
>            return {'polymorphic_identity': cls.__name__}
>
> class Inherits(InheritMixin):
>     @declared_attr
>     def id(cls):
>         super_id = super(Inherits, cls).id
>         return Column(Integer, ForeignKey(super_id),primary_key = True)
>
> class Person(InheritMixin, Base):
>    discriminator = Column(String(50))
>    name = Column(String(50))
>
> class Engineer(Inherits, Person):
>    job = Column(String(50))
>
>
> this should be in the docs so I've added ticket #2471 to handle this.
>
> > 
> > Cheers, Lars
> > 
> > 
> > On Apr 19, 4:13 pm, Michael Bayer <[email protected]> wrote:
> >> On Apr 19, 2012, at 6:23 AM, lars van gemerden wrote:
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >>> I am trying to my my joined inheritance code clearer, for the dynamic
> >>> generation of sa classes and tried to do something like this:
> >> 
> >>> class InheritMixin(object):
> >> 
> >>>    @declared_attr
> >>>    def __tablename__(cls):
> >>>        return cls.__name__
> >>>    @declared_attr
> >>>    def id(cls):
> >>>        if cls.__name__ == 'Object':
> >>>            return Column(Integer, primary_key = True)
> >>>        else:
> >>>            print 'in id: ', cls.__name__, cls.__bases__[0].__name__
> >>>            return Column(Integer,
> >>> ForeignKey(cls.__bases__[0].__name__ + '.id'), primary_key = True)
> >>>    @declared_attr
> >>>    def __mapper_args__(cls):
> >>>        if cls.__name__ == 'Object':
> >>>            return {'polymorphic_on': 'discriminator'}
> >>>        else:
> >>>            print 'in mapper_args: ', cls.__name__,
> >>> cls.__bases__[0].__name__
> >>>            return {'polymorphic_identity': cls.__name__,
> >>>                    'inherit_condition': (cls.id ==
> >>> cls.__bases__[0].id)}
> >> 
> >>> Object = type('Object', (Base, InheritMixin), clsdict)
> >> 
> >>> Where Object should be the (not necessarily direct) baseclass of all
> >>> inheriting classes. However I get errors: "Mapper Mapper|person|person
> >>> could not assemble any primary key columns for mapped table 'Join
> >>> object on Object(65389120) and person(65428224)' " etc ..
> >> 
> >> im not sure of the cause of that error, can you attach a full test case 
> which illustrates this message being generated ?
> >> 
> >> 
> >> 
> >>> I noticed that the method __mapper_args__(cls) is always called before
> >>> id(cls) (which is never called, probably due to the error.
> >> 
> >> the __mapper_args__(cls) method here directly calls upon .id, so if you 
> see .id() not being called it suggests some other form of .id is being used.
> >> 
> >> Is it possible that Base or something else has a conflicting "id" 
> attribute?
> >> 
> >> 
> >> 
> >>> Also, is there a way to add the discriminator column to the mixin (if
> >>> i just directly add it to the declaration, this gave another maybe
> >>> related error)?
> >> 
> >> maybe, let's start with the general idea of the mixin you're going to 
> send me as a working script.
> > 
> > -- 
> > 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/-/gi8kfTzZZnwJ.
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.

Reply via email to