Ahh ok i already asumed that it has something to do with the "declarative"
approch. I think i will postpone that feature in my app until 1.0 is
released.

Thanks Josip



On 4 November 2014 17:50, Michael Bayer <mike...@zzzcomputing.com> wrote:

> OK, coffee has been applied.    This mapping can be done in 0.9 but only
> if you use classical mappings, AbstractConcreteBase and declarative aren’t
> ready yet.   In 1.0, I made a lot of improvements (see
> http://docs.sqlalchemy.org/en/latest/changelog/migration_10.html#improvements-to-declarative-mixins-declared-attr-and-related-features)
> that manage to get this to work using a fully declarative approach.  A
> minimal example is below.  In particular, you *don’t* want to have a
> “polymorphic_on” column added to any specific table when using concrete
> mappings, there’s no base table that’s shared.  The AbstractConcreteBase
> produces this “polymorphic_on” for you, and it’s only part of the
> “polymorphic union” query you see in the SQL output of the script:
>
>
> from sqlalchemy import Column, String, Integer, create_engine, ForeignKey,
> Float
> from sqlalchemy.orm import Session, relationship
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy.orm.collections import attribute_mapped_collection
> from sqlalchemy.ext.declarative import declared_attr, AbstractConcreteBase
>
>
> Base = declarative_base()
>
>
> class Mammut(Base):
>     __tablename__ = "mammut"
>
>     id = Column(Integer, primary_key=True)
>     nodes = relationship(
>         'TreeNode',
>         lazy='dynamic',
>         back_populates='mammut',
>     )
>
>
> class TreeNode(AbstractConcreteBase, Base):
>     id = Column(Integer, primary_key=True)
>     name = Column(String)
>
>     @declared_attr
>     def __tablename__(cls):
>         if cls.__name__ == 'TreeNode':
>             return None
>         else:
>             return cls.__name__.lower()
>
>     @declared_attr
>     def __mapper_args__(cls):
>         return {'polymorphic_identity': cls.__name__, 'concrete': True}
>
>     @declared_attr
>     def parent_id(cls):
>         return Column(Integer, ForeignKey(cls.id))
>
>     @declared_attr
>     def mammut_id(cls):
>         return Column(Integer, ForeignKey('mammut.id'))
>
>     @declared_attr
>     def mammut(cls):
>         return relationship("Mammut", back_populates="nodes")
>
>     @declared_attr
>     def children(cls):
>         return relationship(
>             cls,
>             back_populates="parent",
>             collection_class=attribute_mapped_collection('name'),
>         )
>
>     @declared_attr
>     def parent(cls):
>         return relationship(
>             cls, remote_side="%s.id" % cls.__name__,
>             back_populates='children')
>
>
> class IntTreeNode(TreeNode):
>     value = Column(Integer)
>
>
> class FloatTreeNode(TreeNode):
>     value = Column(Float)
>     miau = Column(String(50), default='zuff')
>
> e = create_engine("sqlite://", echo=True)
> Base.metadata.create_all(e)
>
> session = Session(e)
>
> root = IntTreeNode(name='root')
> IntTreeNode(name='n1', parent=root)
> n2 = IntTreeNode(name='n2', parent=root)
> IntTreeNode(name='n2n1', parent=n2)
>
> m1 = Mammut()
> m1.nodes.append(n2)
> m1.nodes.append(root)
>
> session.add(root)
> session.commit()
>
>
> session.close()
>
> root = session.query(TreeNode).filter_by(name='root').one()
> print root.children
>
>
> that polymorphic query at the bottom looks like the following, note that
> the “type”, which is our polymorphic_on, is a virtual column:
>
> SELECT pjoin.id AS pjoin_id, pjoin.name AS pjoin_name, pjoin.value AS
> pjoin_value, pjoin.miau AS pjoin_miau, pjoin.mammut_id AS pjoin_mammut_id,
> pjoin.parent_id AS pjoin_parent_id, pjoin.type AS pjoin_type
> FROM (SELECT floattreenode.id AS id, floattreenode.name AS name,
> floattreenode.value AS value, floattreenode.miau AS miau,
> floattreenode.mammut_id AS mammut_id, floattreenode.parent_id AS parent_id,
> 'FloatTreeNode' AS type
> FROM floattreenode UNION ALL SELECT inttreenode.id AS id, inttreenode.name
> AS name, inttreenode.value AS value, CAST(NULL AS VARCHAR(50)) AS miau,
> inttreenode.mammut_id AS mammut_id, inttreenode.parent_id AS parent_id,
> 'IntTreeNode' AS type
> FROM inttreenode) AS pjoin
> WHERE pjoin.name = ?
>
>
>
>
>
>
>
>
> On Nov 4, 2014, at 10:33 AM, Michael Bayer <mike...@zzzcomputing.com>
> wrote:
>
> there is a lot lot lot going on here.     The example isn’t working in 1.0
> for different reasons, for example.
>
> However lets start with just the error you have, and to do that, lets
> please just show the minimal amount of code to reproduce:
>
> from sqlalchemy import *
> from sqlalchemy.orm import *
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy.ext.declarative import declared_attr, AbstractConcreteBase
>
>
> Base = declarative_base()
>
>
> class Mammut(Base):
>     __tablename__ = "mammut"
>
>     id = Column(Integer, primary_key=True)
>     nodes = relationship(
>         'TreeNode',
>         backref='mammut',
>     )
>
>
> class TreeNode(AbstractConcreteBase, Base):
>     id = Column(Integer, primary_key=True)
>     name = Column(String(50), nullable=False)
>     depth = Column(Integer, default=0)
>     data_type = Column(String(50))
>
>     @declared_attr
>     def mammut_id(cls):
>         return Column(Integer, ForeignKey('mammut.id'))
>
>     def __init__(self, name, value=None, parent=None):
>         self.name = name
>         self.parent = parent
>         self.depth = 0
>         self.value = value
>         if self.parent:
>             self.depth = self.parent.depth + 1
>
>
> class IntTreeNode(TreeNode):
>     value = Column(Integer)
>
>     __tablename__ = 'int'
>     __mapper_args__ = {"concrete": True, "polymorphic_identity": 'int'}
>
>
> class FloatTreeNode(TreeNode):
>     value = Column(Float)
>     miau = Column(String(50), default='zuff')
>
>     __tablename__ = 'float'
>     __mapper_args__ = {"concrete": True, "polymorphic_identity": 'float'}
>
> node = IntTreeNode('rootnode', value=2)
>
> mut = Mammut()
> mut.nodes.append(node)
>
> The issue is that you can’t just do a single “backref” to concrete
> classes.  You have to use the instructions at
> http://docs.sqlalchemy.org/en/rel_0_9/orm/inheritance.html#relationships-with-concrete-inheritance
>  to
> create each reference from IntTreeNode / FloatTreeNode etc. back.
>
> This has been improved in 1.0.   We can say:
>
> class Mammut(Base):
>     __tablename__ = "mammut"
>
>     id = Column(Integer, primary_key=True)
>     nodes = relationship(
>         'TreeNode',
>         back_populates='mammut',
>     )
>
> class TreeNode(AbstractConcreteBase, Base):
>     id = Column(Integer, primary_key=True)
>     name = Column(String(50), nullable=False)
>     depth = Column(Integer, default=0)
>     data_type = Column(String(50))
>
>     @declared_attr
>     def mammut_id(cls):
>         return Column(Integer, ForeignKey('mammut.id'))
>
>     @declared_attr
>     def mammut(cls):
>         return relationship("Mammut", back_populates='nodes')
>
>     def __init__(self, name, value=None, parent=None):
>         self.name = name
>         self.parent = parent
>         self.depth = 0
>         self.value = value
>         if self.parent:
>             self.depth = self.parent.depth + 1
>
> however in 0.9, this won’t work, and after some experimentation I don’t
> think it’s possible in 0.9 to have a backref pointing to an
> AbstractConcreteBase, sorry.
>
> Also, the attempt to make a self-referential relationship from TreeNode to
> itself is also not possible in the way you are attempting.  There is no
> TreeNode table, so this would require distinct relationships and foreign
> keys on each concrete table, however I’m not getting that to work either.
>
> I think you might not intend to use AbstractConcreteBase here in any case
> as it seems like you want there to be a base table (this creates one?).
>
>
> I’ll try to look more later but overall there’s kind of too much going on
> here and concrete inheritance is not very easy to use, sorry.
>
>
>
>
>
>
>
>
>
>
>
>
> On Nov 4, 2014, at 7:28 AM, delijati <delij...@gmail.com> wrote:
>
> Hello,
>
> i posted my question on stakoverflow. So to not repeat myself:
>
>
> https://stackoverflow.com/questions/26724897/adjacency-list-abstract-base-class-inheritance-used-in-relationship
>
> Josip
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
>
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
>
>
>  --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to