ORM 3 level hieracrchy

32 views
Skip to first unread message

Richard Damon

unread,
Sep 2, 2020, 9:08:11 PM9/2/20
to sqlal...@googlegroups.com
I am getting the following error:

SAWarning: Implicitly combining column Node.node_id with column
Name.node_id under attribute 'node_id'.  Please configure one or more
attributes for these same-named columns explicitly.

In my case I am using poymorphic classes by joining with the ORM. Node
is the base of the hierarchy (derived from declarative_base), then I
have a class Property derived from it, and a class Name derived from
Property. Each class has a primary_key named node_id, with a foreign key
constraint one step done the hierarchy. I have also tried making all the
Foreign key constraints point to Node.node_id and it doesn't make a
difference.

It is just a warning, and the lookup does seem to make the double join,
so it doesn't seem to be a big problem, but it seems it want me to
configure something for these, but I am not sure what.

Two level inheritance is working just fine, it is just where it hits the
3rd level that it seems to want something explicit.

--
Richard Damon

Mike Bayer

unread,
Sep 2, 2020, 9:39:49 PM9/2/20
to noreply-spamdigest via sqlalchemy
there's an FAQ entry, a little bit dated but the general idea is still there, at:


for joined table inheritance, where Name(Node) -> node_id are FK -> PK, the warning isn't emitted.  so please share the mapping if it is doing this when it shouldnt.
-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper


To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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+...@googlegroups.com.


Richard Damon

unread,
Sep 2, 2020, 10:08:53 PM9/2/20
to sqlal...@googlegroups.com
Here is the code, note in all cases node_id  are foreign key/primary_key
to a primary_key down the chain:


class Base:
    """Base Class for SQLAlchemy ORM Classes"""
    @declared_attr
    def __tablename__(cls):
        """Default the Table Name to the Class Name"""
        return cls.__name__

Base = declarative_base(cls=Base)

class Node(Base):
    """Class repesents the base of the User Data types."""
    node_id = Column(Integer, primary_key=True)
    type_name = Column(String(255), nullable=False)  # todo should come
from type_id

    @declared_attr
    def __mapper_args__(cls):
        if cls.__name__ == 'Node' :
            __mapper_args__ = {
                'polymorphic_identity': 'Node',
                'polymorphic_on': cls.type_name,
            }
        else:
            __mapper_args__ = {
                'polymorphic_identity': cls.__tablename__,
                "inherit_condition": cls.node_id == Node.node_id
            }
        return __mapper_args__

class Property(Node):
    node_id = Column(Integer, ForeignKey('Node.node_id'), primary_key=True)
    ref_id = Column(Integer, ForeignKey('Node.node_id'))

class Name(Property):
    node_id = Column(Integer, ForeignKey('Property.node_id'),
primary_key=True)
>> <mailto:sqlalchemy+...@googlegroups.com>.
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>  
> http://www.sqlalchemy.org/
>  
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> 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+...@googlegroups.com
> <mailto:sqlalchemy+...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sqlalchemy/e07cc259-2216-4ece-baf9-daabebf4ac00%40www.fastmail.com
> <https://groups.google.com/d/msgid/sqlalchemy/e07cc259-2216-4ece-baf9-daabebf4ac00%40www.fastmail.com?utm_medium=email&utm_source=footer>.


--
Richard Damon

Mike Bayer

unread,
Sep 2, 2020, 11:30:23 PM9/2/20
to noreply-spamdigest via sqlalchemy
well you are giving Name an inherit condition that conflicts with how you set up the foreign key. 

Name.node_id FKs to Property.node_id

but then inherit condition is Name.node_id -> Node.node_id

There seems to be a little unsmoothness to actually being able to configure it that way, that is, skipping over Property.node_id, but in this case your FKs make it clear what you're going for which is the "normal' setup of Name->Property->Node so you can remove "inherit condition" from Name and it works fine:

class Name(Property):
    __tablename__ = 'Name'

    node_id = Column(Integer, ForeignKey("Property.node_id"), primary_key=True)

    __mapper_args__ = {
        "polymorphic_identity": "Name",
    }


or set it:

class Name(Property):
    __tablename__ = 'Name'

    node_id = Column(Integer, ForeignKey("Property.node_id"), primary_key=True)

    __mapper_args__ = {
        "polymorphic_identity": "Name",
        "inherit_condition": node_id == Property.node_id,
To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.


Richard Damon

unread,
Sep 3, 2020, 7:24:59 AM9/3/20
to sqlal...@googlegroups.com
I've tried taking my code and changing the ForeignKey to be to Node, and
that doesn't change the Warning.
Is the problem trying to DRY with the @declared_attr __mapper__?
>> Richard Damon

--
Richard Damon

Mike Bayer

unread,
Sep 3, 2020, 9:59:28 AM9/3/20
to noreply-spamdigest via sqlalchemy
you might be able to use the declared_attr __mapper__ but you would need to omit that erroneous inherit condition if the class is "Name".   IMO it would be easier to follow and understand by simply using explicit __mapper_args__ on each class but this depends on what you're doing.
-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper


To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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+...@googlegroups.com.

Richard Damon

unread,
Sep 3, 2020, 10:24:31 AM9/3/20
to sqlal...@googlegroups.com
I have a large number (around a dozen or more, and likely to grow) of
derived classes, so I was hoping to cut down repetition with the
@declared_attr.
So, 3rd (or farther) derived classes need the inherit_condition to point
to their immediate base. That does seem to remove the warning.
>> <mailto:sqlalchemy+...@googlegroups.com>.
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>  
> http://www.sqlalchemy.org/
>  
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> 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+...@googlegroups.com
> <mailto:sqlalchemy+...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sqlalchemy/1a45c6d0-f85f-440a-af1f-47fa9b254e5b%40www.fastmail.com
> <https://groups.google.com/d/msgid/sqlalchemy/1a45c6d0-f85f-440a-af1f-47fa9b254e5b%40www.fastmail.com?utm_medium=email&utm_source=footer>.


--
Richard Damon

Mike Bayer

unread,
Sep 3, 2020, 10:25:37 AM9/3/20
to noreply-spamdigest via sqlalchemy
yup that was the idea
To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.


Richard Damon

unread,
Sep 3, 2020, 12:57:27 PM9/3/20
to sqlal...@googlegroups.com
It looks like I can keep the @declared_attr by using
 "inherit_condition": cls.node_id == cls.__mro__[1].node_id

The __mro__[1] gets the leftmost (or only) parent class. As long as I
make sure that it the inheritance tree (and I wasn't planning on
multiple inheritance here) I should be ok.
Richard Damon

Reply all
Reply to author
Forward
0 new messages