what version of SQLA is that ? I cannot reproduce.   test case:

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

Base= declarative_base()

class Person(Base):
   id = Column(Integer, primary_key=True)
   type = Column('type', String(50))

   @declared_attr
   def __tablename__(cls):
       if has_inherited_table(cls):
           return None
       return cls.__name__.lower()

   @declared_attr
   def __mapper_args__(cls):
       if cls.__name__ == 'Person':
           mapper_args = {}
           mapper_args['polymorphic_on'] = cls.type
           return mapper_args
       else:
           return {"polymorphic_identity": cls.__name__}

class Mixin(object):

   @declared_attr
   def target_id(cls):
       return Column('target_id', ForeignKey('target.id'))

   @declared_attr
   def target(cls):
       return relationship("Target")

class Engineer(Person, Mixin):
    pass

class Target(Base):
    __tablename__ = 'target'
    id = Column(Integer, primary_key=True)

configure_mappers()

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
s.add_all([
    Engineer(),
    Engineer(target=Target())
])
print s.query(Engineer, Target).outerjoin(Engineer.target).all()


output:

2012-04-16 10:34:51,368 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2012-04-16 10:34:51,369 INFO sqlalchemy.engine.base.Engine INSERT INTO target 
DEFAULT VALUES
2012-04-16 10:34:51,369 INFO sqlalchemy.engine.base.Engine ()
2012-04-16 10:34:51,369 INFO sqlalchemy.engine.base.Engine INSERT INTO person 
(type, target_id) VALUES (?, ?)
2012-04-16 10:34:51,370 INFO sqlalchemy.engine.base.Engine ('Engineer', None)
2012-04-16 10:34:51,370 INFO sqlalchemy.engine.base.Engine INSERT INTO person 
(type, target_id) VALUES (?, ?)
2012-04-16 10:34:51,370 INFO sqlalchemy.engine.base.Engine ('Engineer', 1)
2012-04-16 10:34:51,371 INFO sqlalchemy.engine.base.Engine SELECT person.id AS 
person_id, person.type AS person_type, person.target_id AS person_target_id, 
target.id AS target_id 
FROM person LEFT OUTER JOIN target ON target.id = person.target_id 
WHERE person.type IN (?)
2012-04-16 10:34:51,371 INFO sqlalchemy.engine.base.Engine ('Engineer',)
[(<__main__.Engineer object at 0x1014ff090>, None), (<__main__.Engineer object 
at 0x1014ffa10>, <__main__.Target object at 0x1014ffed0>)]




On Apr 16, 2012, at 12:17 AM, Amos wrote:

> I am attempting to use STI with mixins on the derived/inheriting
> classes. If the mixin has a simple Column, everything works great. But
> when I have a ForeignKey on the Column, and therefore use the
> `declared_attr` decorator, I get an exception when I attempt to query
> the child collection.
> 
> For the example below, querying the Engineer class throws the
> following exception:
> 
> InvalidRequestError: Class <class 'Person'> does not have a mapped
> column named 'target_id'
> 
> Here's some code:
> 
>    class Person(Base):
>        id = Column(Integer, primary_key=True)
>        type = Column('type', String(50))
> 
>        @declared_attr
>        def __tablename__(cls):
>            if has_inherited_table(cls):
>                return None
>            return cls.__name__.lower()
> 
>        @declared_attr
>        def __mapper_args__(cls):
>            if cls.__name__ == 'Person':
>                mapper_args = {}
>                mapper_args['polymorphic_on'] = cls.type
>                return mapper_args
>            else:
>                return {"polymorphic_identity": cls.__name__}
> 
>    class Mixin(object):
>        simple_column = Column(Integer, nullable=True) # This column
> is mapped correctly
> 
>        @declared_attr
>        def target_id(cls): # But when I have a column with a
> ForeignKey, and I used `declared_attr` - everything breaks down
>            return Column('target_id', ForeignKey('target.id'))
> 
>        @declared_attr
>        def target(cls): # Relationships also work correctly, if
> target_id is defined in the Person class
>            return relationship("Target")
> 
>    class Engineer(Person, Mixin):
>        pass
> 
> I know I can get around this by declaring the target_id on the Person
> class but then I lose the encapsulation provided by the Mixin class.
> Why does declaring a simple Column on the Mixin work perfectly, but
> fail when declaring a column using the `declared_attr` decorator?
> 
> -- 
> 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