question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multiple many-to-many self referencing relationships

See original GitHub issue

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the SQLModel documentation, with the integrated search.
  • I already searched in Google “How to X in SQLModel” and didn’t find any information.
  • I already read and followed all the tutorial in the docs and didn’t find an answer.
  • I already checked if it is not related to SQLModel but to Pydantic.
  • I already checked if it is not related to SQLModel but to SQLAlchemy.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

from typing import List, Optional

from sqlmodel import Field, Relationship, Session, SQLModel, create_engine


class UserLink(SQLModel, table=True):
    parent_id: Optional[int] = Field(
        default=None, foreign_key="user.id", primary_key=True
    )
    child_id: Optional[int] = Field(
        default=None, foreign_key="user.id", primary_key=True
    )


class User(SQLModel, table=True):
    id: int = Field(default=None, primary_key=True)
    parents: List["User"] = Relationship(back_populates="children", link_model=UserLink)
    children: List["User"] = Relationship(back_populates="parents", link_model=UserLink)


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url, echo=True)
SQLModel.metadata.create_all(engine)


with Session(engine) as session:
    user_1 = User(id=1)
    session.add(user_1)

    user_2 = User(id=2, parents=[user_1])
    session.add(user_2)

    session.commit()

    session.refresh(user_1)
    session.refresh(user_2)

    assert len(user_1.children) == 1
    assert len(user_1.parents) == 0

    assert len(user_2.children) == 0
    assert len(user_2.parents) == 1

Description

I am trying to create a model with multiple many-to-many relationships referencing self. See example code.

My code raises this error:

sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship User.parents - there are multiple foreign key paths linking the tables via secondary table 'userlink'.  Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference from the secondary table to each of the parent and child tables

My code is based on the many-to-many example in the docs.

As the error is coming from sqlalchemy it might also be an sqlalchemy issue but as it is raised by an example that is coming from the docs I think I might be using SQLmodel incorrectly.

I did read the sqlalchemy docs on many-to-many relationships but they did not help me.

This issue on stackoverflow seems related but I cannot figure out how to apply it to my situation.

Questions:

  • Am I correct in the assumption that I need to use many-to-many relationships with a link model?
  • …or could the same be achieved by using a one-to-many with back_populates?
  • The sqlalchemy error is quite cryptic (at least to me). I seem to already have specified the foreign_key on the UserLink model columns but apparently I need to specify it differently or somewhere else as well. What else is needed to make this work?

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.5

Additional Context

No response

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:3
  • Comments:6

github_iconTop GitHub Comments

11reactions
maresbcommented, Sep 12, 2021

I’m fairly new to this, but I seem to have managed to get it to work with

class User(SQLModel, table=True):
    id: int = Field(default=None, primary_key=True)
    parents: List["User"] = Relationship(
        back_populates="children",
        link_model=UserLink,
        sa_relationship_kwargs=dict(
            primaryjoin="User.id==UserLink.child_id",
            secondaryjoin="User.id==UserLink.parent_id",
        ),
    )
    children: List["User"] = Relationship(
        back_populates="parents",
        link_model=UserLink,
        sa_relationship_kwargs=dict(
            primaryjoin="User.id==UserLink.parent_id",
            secondaryjoin="User.id==UserLink.child_id",
        ),
    )

I’m not sure whether or not this is the “correct” way. I’m curious about what more expert people have to say.

My inspiration was Self-Referential Many-to-Many Relationship from the SQLAlchemy docs.

3reactions
AartGoossenscommented, May 18, 2022

@Iionsroar I think this is not related to this issue, but this one https://github.com/tiangolo/sqlmodel/pull/322.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Many to Many Self referencing relationship - sql - Stack Overflow
I'm attempting to create a library database using SQL in which one book_id recommends another book_id number. The table I have created is...
Read more >
Self-referencing many to many — Ecto v3.9.2 - HexDocs
many_to_many/3 is used to establish the association between two schemas with a join table (or a join schema) tracking the relationship between them....
Read more >
Self-referencing many-to-many through - charles leifer
What I want to talk about in this post is how to create ManyToMany relationships between objects of the same kind, and more...
Read more >
06 - Self referencing - Many To Many relation - with ... - YouTube
repo :https://github.com/Rowadz/sequelize-youtubeI'm using Sequelize v5In these videos about Sequelize ( NodeJS ORM ) I'll cover these ...
Read more >
Modeling self-referencing associations with Hibernate
A typical example is a Person who has other Persons as their parents. You can model it as a uni- or bidirectional many-to-many...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found