tortoise / tortoise/tortoise-orm
"OperationalError: ON clause references tables to its right" on self-refencing join
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 516
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 9
Description
I don't know if this is a bug or an error on my part: I'm trying to construct a follower-followee relationship between two user-profiles. A profile has a one-to-one relation to a user. Here is a minimal example:
from tortoise.models import Model
from tortoise import Tortoise, fields, run_async
class User(Model):
id = fields.UUIDField(pk=True)
username = fields.CharField(max_length=20, unique=True)
class Profile(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=255)
following: fields.ManyToManyRelation["Profile"] = fields.ManyToManyField(
"models.Profile", related_name="followers", through="followtable",
backward_key="follower", forward_key="followee"
)
followers: fields.ManyToManyRelation["Profile"]
owner: fields.OneToOneRelation[User] = fields.OneToOneField(
model_name="models.User", related_name="profile"
)
async def run():
await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]})
await Tortoise.generate_schemas()
# Set up follower identity: Frank Drebin
user_drebin = await User.create(username="zucker_fan")
profile_drebin = await Profile.create(name="Frank Drebin", owner=user_drebin)
user_drebin_id = user_drebin.id
# Set up followee identity: Terry Gilliam
user_gilliam = await User.create(username="monty_fan")
profile_gilliam = await Profile.create(name="Terry Gilliam", owner=user_gilliam)
await profile_gilliam.followers.add(profile_drebin)
await profile_gilliam.save()
# Now I want to find out who Frank Drebin follows:
# This works but involves two queries:
p = await Profile.get(owner_id=user_drebin_id)
who_drebin_follows = await p.following
print(who_drebin_follows)
# This doesn't
print(await Profile.filter(followers__owner_id = user_drebin_id))
if __name__ == "__main__":
run_async(run())
The second query should go through the related profiles of the followers and retrieve the ones with the given user id, but it just gets the error:
tortoise.exceptions.OperationalError: ON clause references tables to its right
This is the generated SQL:
SELECT "profile"."name","profile"."owner_id","profile"."id" FROM "profile"
LEFT OUTER JOIN "followtable" ON "profile2"."id"="followtable"."followee"
LEFT OUTER JOIN "profile" "profile2" ON "followtable"."follower"="profile2"."id"
WHERE "profile2"."owner_id"='dad3f7d3-095c-41c8-868f-545d4947cf7a';
But I'm looking for a way to kind of turn that statement inside out and fetch the profile2 part like this:
SELECT profile2.* FROM profile
JOIN followtable ON profile.id = followtable.follower
JOIN profile profile2 ON profile2.id=followtable.followee
WHERE profile.owner_id = 'dad3f7d3-095c-41c8-868f-545d4947cf7a';
What exactly am I missing in the second query statement?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the minimal Python example and the SQL generated by Profile.filter(followers__owner_id=user_drebin_id). Compare its join order with the expected SQL and trace how the self-referencing relation is translated. Done means the filter returns the followed profiles without the ON-clause OperationalError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, sql, sqlite
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100