sqlalchemyflask-sqlalchemy

How to query child tables belonging to particular parent


Is it possible to get one/all deep-nestend child tables in one-to-many hierarchy?

Say, a user has been logged.

u = db.session.execute(db.select(U).where(U.email == 'user@example.com')).scalar()

And I'd like to query one/all X3 tables within the user. How can I do it?

                    <- X3 ->
    <- X1 -><- X2 ->
                    <- X3 ->
-- U1 ->
                        <- X3 ->
        <- X1 -><- X2 ->
                        <- X3 ->

--------------------------------

                        <- X3 ->
        <- X1 -><- X2 ->
                        <- X3 ->
-- U2 ->
                        <- X3 ->
        <- X1 -><- X2 ->
                        <- X3 ->

class U(UserMixin, db.Model):
    id: Mapped[int] = mapped_column(primary_key=True)
    email: Mapped[str] = mapped_column(String(64), index=True, unique=True)
    # ...
    x1: Mapped[list["X1"]] = db.relationship(back_populates="u", cascade='all, delete')

class X1(db.Model):
    id: Mapped[int] = mapped_column(primary_key=True)
    # ...
    u: Mapped["U"] = db.relationship(back_populates="x1", cascade='all, delete')
    u_id: Mapped[int] = mapped_column(ForeignKey("u.id"))
    x2: Mapped[list["X2"]] = db.relationship(back_populates="x1", cascade='all, delete')

class X2(db.Model):
    id: Mapped[int] = mapped_column(primary_key=True)
    # ...
    x1: Mapped["X1"] = db.relationship(back_populates="x2", cascade='all, delete')
    x1_id: Mapped[int] = mapped_column(ForeignKey("x1.id"))
    x3: Mapped[list["X3"]] = db.relationship(back_populates="x2", cascade='all, delete')
    
class X3(db.Model):
    id: Mapped[int] = mapped_column(primary_key=True)
    # ...
    x2: Mapped["X2"] = db.relationship(back_populates="x3", cascade='all, delete')
    x2_id: Mapped[int] = mapped_column(ForeignKey("x2.id"))

Thanks.


Solution

  • Based on what I've understand, like why not join all the tables one by one since they're related like this

    result = db.session.scalars(
        db.select(X3)
        .join(X2)
        .join(X1)
        .join(U)
        .where(U.id == user.id)
    ).all()
    

    You can use also nested loops in case...