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 <mike...@zzzcomputing.com> 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 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.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
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.

Reply via email to