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.