tortoise / tortoise/tortoise-orm
Incorrect filtering using expressions:Q
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 516
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 9
Description
Description
I am experiencing an issue with Tortoise ORM while trying to filter users (User) based on related Performer and Project objects. The code is not working correctly and is not returning the expected results.
To Reproduce
from tortoise import Tortoise, fields
from tortoise.models import Model
from tortoise.expressions import Q
# User, Project, and Performer model definitions
class User(Model):
"""User model"""
id = fields.IntField(pk=True)
username = fields.CharField(max_length=32, unique=True, index=True)
creator: fields.ForeignKeyRelation["User"] = fields.ForeignKeyField(
"models.User", null=True, on_delete=fields.SET_NULL, related_name="children"
)
class Project(Model):
id = fields.IntField(pk=True)
creator: fields.ForeignKeyRelation[User] = fields.ForeignKeyField(
"models.User", related_name="projects"
)
class Performer(Model):
user: fields.ForeignKeyRelation[User] = fields.ForeignKeyField(
"models.User", related_name="performers"
)
project: fields.ForeignKeyRelation[Project] = fields.ForeignKeyField(
"models.Project", related_name="performers"
)
# Initializing Tortoise and creating the schema
await Tortoise.init( # type: ignore
db_url="sqlite://:memory:",
modules={"models": ["__main__"]},
)
await Tortoise.generate_schemas()
# Creating users, projects, and their relationships
user1 = await User.create(username="user1")
project = await Project.create(creator=user1)
user2 = await User.create(username="user2", creator=user1)
await User.create(username="user3", creator=user1)
await Performer.create(user=user2, project=project)
# Executing queries and getting results
performers = Q(performers__project=project)
res1 = await project.creator.children.filter(performers)
# Expected result: [<User: 2>]
res2 = await project.creator.children.filter(~performers)
# Expected result: [<User: 3>]
children = Q(creator=project.creator)
res3 = await User.filter(children & ~performers)
# Expected result: [<User: 3>]
Expected behavior
Upon executing queries res1, res2, and res3, I expect to get the following results:
- res1: [<User: 2>]
- res2: [<User: 3>]
- res3: [<User: 3>]
Actual Behavior
However, the current behavior of the code leads to incorrect results:
- res1: [<User: 2>] (This is correct)
- res2: [] (Expected: [<User: 3>])
- res3: [] (Expected: [<User: 3>])
Versions
Tortoise ORM: 0.19.3
Python: 3.11.0
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 by running the provided SQLite reproducer with Tortoise ORM 0.19.3 and inspect the Q expressions used in the three User queries. Compare positive and negated relation filters, then verify that res2 and res3 return User 3 without changing the expected res1 result.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, sqlite
- Domain
- database
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100