Skip to content

feat: add contains() operation to QuerySet#2163

Open
seladb wants to merge 10 commits intotortoise:developfrom
seladb:add-contains
Open

feat: add contains() operation to QuerySet#2163
seladb wants to merge 10 commits intotortoise:developfrom
seladb:add-contains

Conversation

@seladb
Copy link
Copy Markdown
Contributor

@seladb seladb commented Apr 1, 2026

Add QuerySet.contains() method for checking if object exists in queryset

Description

Added QuerySet.contains() which checks if a specific model instance exists within a queryset. Implementation includes:

  • QuerySet.contains(obj) method in tortoise/queryset.py that returns a ContainsQuery object
  • ContainsQuery class that extends ExistsQuery and adds filtering by the object's primary key

Motivation and Context

This feature enables checking if a specific model instance belongs to a filtered queryset, useful for membership checks without fetching the full object.

It's also in par with Django API.

How Has This Been Tested?

  • Added test_contains in tests/test_queryset.py covering all cases
  • All existing tests pass

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added the changelog accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 1, 2026

Merging this PR will not alter performance

✅ 24 untouched benchmarks


Comparing seladb:add-contains (7ace03c) with develop (d31209c)

Open in CodSpeed

@seladb seladb marked this pull request as ready for review April 1, 2026 06:58
@seladb seladb changed the title Add contains() operation to QuerySet feat: Add contains() operation to QuerySet Apr 3, 2026
@seladb
Copy link
Copy Markdown
Contributor Author

seladb commented Apr 3, 2026

@abondar MSSQL tests fail randomly, but shouldn't be related to the changes in this PR

@seladb seladb changed the title feat: Add contains() operation to QuerySet feat: add contains() operation to QuerySet Apr 4, 2026
@seladb
Copy link
Copy Markdown
Contributor Author

seladb commented Apr 10, 2026

@abondar this PR is ready for review, can you please take a look? 🙏

@seladb
Copy link
Copy Markdown
Contributor Author

seladb commented Apr 14, 2026

@abondar this PR is ready for review, can you please take a look? 🙏

@abondar @waketzheng a gentle reminder that this PR is ready for review. Do you think you can take a look?

@seladb
Copy link
Copy Markdown
Contributor Author

seladb commented May 6, 2026

@abondar this PR is open for a while, can you please review it?

Comment thread tortoise/queryset.py
use_indexes=self._use_indexes,
)

def contains(self, obj: MODEL) -> ContainsQuery:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like we should add validations around obj here, so that it is same type as queryset, and it's obj.pk is not None - in other case passing such objects can lead to strange behavior

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abondar I'm not sure we have to have to verify the object has the same type as the queryset because we have that in the type-hint, but I can add it if you think it's needed:

image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking if obj.pk exists was added in 7ace03c

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am concerned about case where object of other model would be passed and it will silently try to check against that other model id, maybe even returning True, which is definetely not what we want

Comment thread tortoise/queryset.py Outdated
Comment on lines +1505 to +1508
pk_attr = self.model._meta.pk_attr
source_pk_attr = self.model._meta.fields_map[pk_attr].source_field or pk_attr
pk = Field(source_pk_attr)
self.query = self.query.where(pk.eq(self._obj.pk))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pk_value = self.model._meta.fields_map[pk_attr].to_db_value(self._obj.pk, None) - we need to add conversion, to be better ready for custom id types

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also we have self.model._meta.db_pk_column - to use it directly instead of calculating

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 7ace03c

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You didn't changed it to use "to_db_value" - is it intentional?

@seladb seladb requested a review from abondar May 8, 2026 05:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants