On Aug 16, 2010, at 4:20 AM, jean-philippe serafin wrote:

> AbstractA is AbstractB "base" class.........
> AbstractB is ClassA "base" class............
> 
> Everything work fine in this case.
> 
> I just want to set 'polymorphic_identity' on each inheritance level 
> if I set by hand : update abstract_a set class_name = 'class_a' :
> AbstractA.query.first() give me back a ClassA object


The reason you can't easily set "class_name" on the base is that you've named 
the attribute the same thing on both AbstractA and AbstractB.  So 
AbstractB.class_name will never affect the basemost attribute on AbstractA.   
If you name them differently, your constructor can ensure they are set:

   def __init__(self, label):
       self.label = label
       self.class_name_a = self.class_name_b = self.__tablename__

But what works better, merge them on AbstractB (still remove the unnecessary 
polymorphic_on from B, however), the value gets propagated to that of AbstractB:

class AbstractA(Base):

   __tablename__ = "abstract_a"

   id = Column(Integer, primary_key=True)
   class_name = Column('class_name', String(50))

   __mapper_args__ = {
       'polymorphic_on': class_name,
   }

class AbstractB(AbstractA):

   __tablename__ = "abstract_b"

   id = Column(Integer, ForeignKey('abstract_a.id'),primary_key=True)
   class_name = column_property(Column('class_name', String(50)), 
AbstractA.__table__.c.class_name)

   __mapper_args__ = {
       'polymorphic_identity': __tablename__,
   }


Note however, it is not possible to load a ClassA object without querying at 
the very least "abstract_a".   So the "class_name" column of "abstract_a" is 
always available with regular polymorphic querying.  Its redundant and less 
normalized to have "class_name" on both tables with the same value  
(technically its not normalized in the first place to have a discriminator 
column at all, though it has a dramatically positive effect on our ability to 
locate subtypes without many outer joins).   So there's no reason I can think 
of why you'd want class_name on B.   But even if you did, there's still no 
reason to ever put polymorphic_on on a non-base table with the current 
implementation, and that should still be changed to emit a warning (#1880)- 
even here it would have alerted you to the issue.



> 
> 
> 2010/8/15 Michael Bayer <mike...@zzzcomputing.com>
> 
> On Aug 15, 2010, at 6:52 AM, jean-philippe serafin wrote:
> 
> > Hi,
> >
> > I've got a class mapping with two polymorphic inheritance :
> >
> > class AbstractA(Base):
> >
> >    __tablename__ = "abstract_a"
> >
> >    id = Column(Integer, primary_key=True)
> >    class_name = Column('class_name', String(50))
> >
> >    __mapper_args__ = {
> >        'polymorphic_on': class_name,
> >    }
> >    #some stuff here
> >
> > class AbstractB(AbstractA):
> >
> >    __tablename__ = "abstract_b"
> >
> >    id = Column(Integer, ForeignKey('abstract_a.id'),
> > primary_key=True)
> >    class_name = Column('class_name', String(50))
> >
> >    __mapper_args__ = {
> >        'polymorphic_on': class_name,
> >        'polymorphic_identity': __tablename__,
> >    }
> >    #some stuff here
> >
> > class ClassA(AbstractB):
> >
> >    __tablename__ = "table_a"
> >    __mapper_args__ = {
> >        'polymorphic_identity': __tablename__,
> >    }
> >
> >    id = Column(Integer, ForeignKey('abstract_b.id'),
> > primary_key=True)
> >    label = Column('label', String(50))
> >
> >    def __init__(self, label):
> >        self.label = label
> >
> > I persist a ClassA object :
> >
> > object = ClassA('toto')
> > db_session.add(object)
> > db_session.commit()
> >
> > When I try to reload the object like this :
> >
> > reloaded_object = AbstractB.query.first()
> >
> > I get back a ClassA object (just fine)
> >
> > but when I try to reload like this :
> >
> > reloaded_object = AbstractA.query.first()
> >
> > I get back a AbstractA object because abstract_a.class_name has not
> > been set to polymorphic_identity.
> >
> > Is this an issue or expected work?
> 
> polymorphic_on only goes on the base class.    SQLA should be changed to 
> raise an error on the setup you have above.
> 
> 
> >
> > --
> > You received this message because you are subscribed to the Google Groups 
> > "sqlalchemy" group.
> > To post to this group, send email to sqlalch...@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 sqlalch...@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 sqlalch...@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 sqlalch...@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