composite secondary join variant

9 views
Skip to first unread message

Jonathan Vanasco

unread,
Apr 23, 2020, 8:01:18 PM4/23/20
to sqlalchemy
i'm stuck on a variant of the Composite Secondary Join (https://docs.sqlalchemy.org/en/13/orm/join_conditions.html#composite-secondary-joins)

I hope someone can see what my tired eyes are missing. I'm fairly certain the issue is in `secondary' and 'secondaryjoin'.  I've tried a handful of variants I thought would work, but trigger this error:

sqlalchemy.exc.InvalidRequestError: Class <class '__main__.C'> does not have a mapped column named 'get_children'

I've used this pattern with much luck in the past: `primaryjoin` goes from the base class to whatever I build the secondary/secondary join from. 

I've distilled the relationship pattern as below:

* `A` does not fkey onto anything.
* `B` fkeys onto `A`
* The intended relationship on `A` is a list of `C` items, which are related to `B` through an association table

I can build out a the relationship from B, and I could probably mount it onto A with an association_proxy, but I'd like to understand what I'm doing wrong with the `relationship` off A.  This is puzzling me.

Thanks in advace.


import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Integer
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Base = declarative_base()
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class A(Base):
    __tablename__
= 'a'
    id
= Column(Integer, primary_key=True)


    cs
= relationship(
       
"C",
        primaryjoin
="A.id == B.a_id",
        secondary
="join(B, B2C, B.id == B2C.b_id)."
                 
"join(B2C, C, B2C.c_id == C.id)",
       
# secondaryjoin="and_(C.id == B2C.c_id)",
        viewonly
=True
       
)


class B(Base):
    __tablename__
= 'b'
    id
= Column(Integer, primary_key=True)
    a_id
= Column(ForeignKey('a.id'))


class B2C(Base):
    __tablename__
= 'b2c'

    id
= Column(Integer, primary_key=True)
    b_id
= Column(ForeignKey('b.id'))
    c_id
= Column(ForeignKey('c.id'))


class C(Base):
    __tablename__
= 'c'
    id
= Column(Integer, primary_key=True)


engine
= create_engine("sqlite://", echo=True)
Base.metadata.create_all(engine)
sessionFactory
= sessionmaker(bind=engine)
sess
= sessionFactory()

sess
.query(A).join(a.cs).all()


Elmer de Looff

unread,
Apr 24, 2020, 5:17:12 AM4/24/20
to sqlal...@googlegroups.com
Hi Jonathan,

From toying with it a little bit, it looks like you *need* to specify a secondaryjoin when you specify the secondary table. In your example, the secondary does some of the work that the secondaryjoin would need to do. I've created a gist that mirrors your table setup (with some more elaborate naming) that hopefully provides you with what you're looking for.


--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/474ccb9b-6839-47b7-9d38-fd1a7065f7a4%40googlegroups.com.


--

Elmer

Jonathan Vanasco

unread,
Apr 24, 2020, 2:04:26 PM4/24/20
to sqlalchemy
Thanks! That works exactly as I needed.  I knew there was a problem in the secondaryjoin, so i commented it out.

This works more intuitively than my other composite relationships, which are all more complex. The joining you used is:

primaryjoin: A->B
secondaryjoin: B->B2C
secondary: B2C->C

Reply all
Reply to author
Forward
0 new messages