this is a bug, ticket #1930, fixed in r36755ba72782.   Note that a similar 
issue exists for joined table inheritance, and a scheme like the below will 
continue to fail if __tablename__ is added to subclasses (this is ticket 
#1931).   The specific "scheme" is that the attribute name of the column in the 
mixin does not match the column name itself.

http://www.sqlalchemy.org/trac/ticket/1930
http://www.sqlalchemy.org/trac/ticket/1931



On Sep 28, 2010, at 12:06 PM, Julien Iguchi-Cartigny wrote:

> Hello Michael,
> 
> Sorry I missing something but still trap in this problem.
> 
> As far as I am:
> 
> class AbstractContainer(Base,AbstractNamed):
>    __tablename__ = 'CM_MEMBER_CONTAINER_T'
>    id = Column('MEMBER_CONTAINER_ID',Integer,primary_key=True)
>    discriminator = Column('CLASS_DISCR', String(100))
>    __mapper_args__ = {'polymorphic_on': discriminator }
> 
> class CourseSet(AbstractContainer):
> 
>    @classproperty
>    def __mapper_args__(self):
>        args = dict()
>        args.update(AbstractContainer.__mapper_args__)
>        args.update({'polymorphic_identity':
> 'org.sakaiproject.coursemanagement.impl.CourseSetCmImpl'})
>        return args
> 
> The inheritance pass is : Course <- AbstractContainer <- AbstractNamed
> <- AbstractPersistence  (see my first email for the definitions of the
> last two classes).
> 
> Still having some trouble:
> 
> sqlalchemy.exc.ArgumentError: Column 'VERSION' on class <class
> '__main__.CourseSet'> conflicts with existing column
> 'CM_MEMBER_CONTAINER_T.VERSION'
> 
> It I understand correctly, AbstractContainer has already mapped all
> columns declared in parent classes. So CourseSet tries to remap
> everything (it herits from Base) but it fails because all column are
> already mapped.
> 
> So I must say something like "hey, let just reuse mapping and table
> definitions from AbstractContainer" but how can i do this ?
> 
> It seems it is very simple from the POV of the documentation, so I
> must deduce the problem comes from the multiple inheritance.
> 
> Cheers,
> 
> Julien.
> 
> PS: This is the full listing of my code:
> 
> from sqlalchemy import create_engine, Column, String, Date, Integer
> from sqlalchemy.orm import sessionmaker
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy.ext.declarative import has_inherited_table
> from sqlalchemy.util import classproperty
> 
> engine = create_engine(
>    'mysql://xxx:y...@localhost:3306/zzz?charset=utf8&use_unicode=0',
>    pool_recycle=3600, echo=True)
> 
> Base = declarative_base()
> 
> class AbstractPersistent(object):
>    version = Column('VERSION', Integer)
>    last_modified_by = Column('LAST_MODIFIED_BY', String(255))
>    last_modified_date = Column('LAST_MODIFIED_DATE', Date)
>    created_by = Column('CREATED_BY', String(255))
>    created_date = Column('CREATED_DATE', Date)
> 
>    def __repr__(self):
>        return "<AbstractPersistent('%s','%s', '%s','%s','%s')>" % \
>            (self.version, self.last_modified_by,
> self.last_modified_date,
>            self.created_by, self.created_date)
> 
> class AbstractNamed(AbstractPersistent):
>    eid = Column('ENTERPRISE_ID', String(255))
>    title = Column('TITLE', String(255))
>    description = Column('DESCRIPTION', String(255))
> 
>    def __repr__(self):
>        return "<AbstractNamed('%s','%s', '%s')>" % \
>            (self.eid, self.title, self.description) + \
>                super(AbstractNamed, self).__repr__()
> 
> class AbstractContainer(Base,AbstractNamed):
>    __tablename__ = 'CM_MEMBER_CONTAINER_T'
>    id = Column('MEMBER_CONTAINER_ID',Integer,primary_key=True)
>    discriminator = Column('CLASS_DISCR', String(100))
>    __mapper_args__ = {'polymorphic_on': discriminator }
> 
> class AcademicSession(Base,AbstractNamed):
>    __tablename__ = 'CM_ACADEMIC_SESSION_T'
>    id = Column('ACADEMIC_SESSION_ID',Integer,primary_key=True)
>    start_date = Column('START_DATE', Date)
>    end_date = Column('END_DATE', Date)
> 
>    def __repr__(self):
>        return "<AcademicSession('%s','%s', '%s')>" % \
>            (self.id, self.start_date, self.end_date) + \
>            super(AcademicSession, self).__repr__()
> 
> class CourseSet(AbstractContainer):
> 
>    @classproperty
>    def __mapper_args__(self):
>        args = dict()
>        args.update(AbstractContainer.__mapper_args__)
>        args.update({'polymorphic_identity':
> 'org.sakaiproject.coursemanagement.impl.CourseSetCmImpl'})
>        return args
> 
> if __name__ == "__main__":
>    Session = sessionmaker(bind=engine)
>    session = Session()
>    academic_sessions = session.query(AcademicSession).all()
>    print(academic_sessions)
>    course_sets = session.query(CourseSet).all()
>    print(course_sets)
> 
> 
> 
> On 27 sep, 23:55, Michael Bayer <[email protected]> wrote:
>> On Sep 27, 2010, at 5:10 PM, Julien Iguchi-Cartigny wrote:
>> 
>>> But How can i do ? It seems i need to define the table in
>>> AsbtractContainer but every time I've an error about already defined
>>> column.
>> 
>> Your original setup seems as though you'd like both CourseSet and 
>> CanonicalCourse to be mapped to the same table using single table 
>> inheritance.   Therefore they both must extend a class that is mapped to the 
>> target table.   So in this case you'd like AbstractContainer to be mapped, 
>> meaning the "Base" superclass should be moved from CourseSet and 
>> CanonicalCourse onto AbstractContainer.
>> 
>> You can then query for AbstractContainer subclasses using 
>> session.query(AbstractContainer).
>> 
>> 
>> 
>> 
>> 
>>> Cheers,
>> 
>>> Julien.
>> 
>>> On Mon, Sep 27, 2010 at 10:30 PM, Michael Bayer
>>> <[email protected]> wrote:
>> 
>>>> On Sep 27, 2010, at 4:21 PM, Julien Iguchi-Cartigny wrote:
>> 
>>>>> Thank you Michael. This solves the problem and... shows a new one.
>> 
>>>>> So this is my update CourseSet
>> 
>>>>>  class CourseSet(Base,AbstractContainer):
>> 
>>>>>      @classproperty
>>>>>      def __mapper_args__(self):
>>>>>          args = dict()
>>>>>          args.update(AbstractContainer.__mapper_args__)
>>>>>          args.update({'polymorphic_identity':
>>>>> 'org.sakaiproject.coursemanagement.impl.CourseSetCmImpl'})
>>>>>          return args
>> 
>>>>> Because there is several discriminant values, I need to create other ones:
>> 
>>>>> class CanonicalCourse(Base,AbstractContainer):
>> 
>>>>>    @classproperty
>>>>>    def __mapper_args__(self):
>>>>>        args = dict()
>>>>>        args.update(AbstractContainer.__mapper_args__)
>>>>>        args.update({'polymorphic_identity':
>>>>> 'org.sakaiproject.coursemanagement.impl.CanonicalCourseCmImpl'})
>>>>>        return args
>> 
>>>>> But this last one will fail, i've the following error message:
>> 
>>>>> sqlalchemy.exc.InvalidRequestError: Table 'CM_MEMBER_CONTAINER_T' is
>>>>> already defined for this MetaData instance.  Specify
>>>>> 'useexisting=True' to redefine options and columns on an existing
>>>>> Table object.
>> 
>>>>> I could use useexisting=True but i don't know if it's the right
>>>>> solution. Any ideas ?
>> 
>>>> that has to do with a Table() statement, or alternatively how you are 
>>>> configuring __table_name__, neither of which are indicated here, so you 
>>>> need to ensure that distinct table names are used whenever a table name is 
>>>> declared.
>> 
>>>>> Cheers,
>> 
>>>>> Julien.
>> 
>>>>> On Mon, Sep 27, 2010 at 1:02 AM, Michael Bayer <[email protected]> 
>>>>> wrote:
>> 
>>>>>> On Sep 26, 2010, at 6:38 PM, Julien Iguchi-Cartigny wrote:
>> 
>>>>>>> Hi,
>> 
>>>>>>> I'm trying to use polymorphic_on with several inheritances:
>> 
>>>>>>>    engine = create_engine(
>>>>>>>        'mysql://xxx:y...@localhost:3306/zzz?charset=utf8&use_unicode=0',
>>>>>>>        pool_recycle=3600, echo=True)
>> 
>>>>>>>    Base = declarative_base()
>> 
>>>>>>>    class AbstractPersistent(object):
>>>>>>>        version = Column('VERSION', Integer)
>>>>>>>        last_modified_by = Column('LAST_MODIFIED_BY', String(255))
>>>>>>>        last_modified_date = Column('LAST_MODIFIED_DATE', Date)
>>>>>>>        created_by = Column('CREATED_BY', String(255))
>>>>>>>        created_date = Column('CREATED_DATE', Date)
>> 
>>>>>>>    class AbstractNamed(AbstractPersistent):
>>>>>>>        eid = Column('ENTERPRISE_ID', String(255))
>>>>>>>        title = Column('TITLE', String(255))
>>>>>>>        description = Column('DESCRIPTION', String(255))
>> 
>>>>>>>    class AbstractContainer(AbstractNamed):
>>>>>>>        __tablename__ = 'CM_MEMBER_CONTAINER_T'
>>>>>>>        id = Column('MEMBER_CONTAINER_ID',Integer,primary_key=True)
>>>>>>>        discriminator = Column('CLASS_DISCR', String(100))
>>>>>>>        __mapper_args__ = {'polymorphic_on': discriminator }
>> 
>>>>>>>    class CourseSet(Base,AbstractContainer):
>>>>>>>        __mapper_args__ = {'polymorphic_identity':
>>>>>>> 'org.sakaiproject.coursemanagement.impl.CourseSetCmImpl'}
>> 
>>>>>> AbstractContainer is not mapped, its a mixin, so its __mapper_args__ are 
>>>>>> not used until a subclass of Base is invoked, which starts up a 
>>>>>> declarative mapping.  Your only mapped class then is CourseSet, which 
>>>>>> has its own __mapper_args__ , that override those of AbstractContainer - 
>>>>>> they are ignored.
>> 
>>>>>> To combine __mapper_args__ from a mapped class with those of a mixin, 
>>>>>> see the example 
>>>>>> athttp://www.sqlalchemy.org/docs/orm/extensions/declarative.html?highli....
>>>>>>   It uses __table_args__ but the same concept of creating a full 
>>>>>> dictionary of arguments applies for __mapper_args__ as well.
>> 
>>>>>> --
>>>>>> 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 
>>>>>> athttp://groups.google.com/group/sqlalchemy?hl=en.
>> 
>>>>> --
>>>>> "Trouble-a-cat limited"
>> 
>>>>> --
>>>>> 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 
>>>>> athttp://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 
>>>> athttp://groups.google.com/group/sqlalchemy?hl=en.
>> 
>>> --
>>> "Trouble-a-cat limited"
>> 
>>> --
>>> 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 
>>> athttp://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 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