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.
