-
Notifications
You must be signed in to change notification settings - Fork 499
fix(queryset): use subquery for DELETE/UPDATE filtering by related fields #2139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
80c15af
fc545b7
b453065
bad1907
677962d
3c575cc
debd9f1
39a4281
f1e6442
f781ec5
5b2fdf4
4727f84
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -519,6 +519,38 @@ async def test_delete_limit_order_by(db, intfields_data): | |
| await IntFields.get(intnum=97) | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_delete_filter_with_foreign_key(db): | ||
| author = await Author.create(name="test") | ||
|
noy-solvin marked this conversation as resolved.
|
||
| await Book.create(name="book1", author=author, rating=5.0) | ||
| await Book.create(name="book2", author=author, rating=4.0) | ||
|
|
||
| author2 = await Author.create(name="test2") | ||
| await Book.create(name="book3", author=author2, rating=5.0) | ||
|
|
||
| # This is the failing query | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove this comment line. |
||
| await Book.filter(author__name="test").delete() | ||
|
|
||
| assert await Book.all().count() == 1 | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_update_filter_with_foreign_key(db): | ||
| author = await Author.create(name="test") | ||
|
noy-solvin marked this conversation as resolved.
|
||
| await Book.create(name="book1", author=author, rating=5.0) | ||
|
|
||
| author2 = await Author.create(name="test2") | ||
| await Book.create(name="book2", author=author2, rating=5.0) | ||
|
|
||
| await Book.filter(author__name="test").update(rating=1.0) | ||
|
|
||
| book = await Book.get(name="book1") | ||
| assert book.rating == 1.0 | ||
|
noy-solvin marked this conversation as resolved.
|
||
|
|
||
| book2 = await Book.get(name="book2") | ||
| assert book2.rating == 5.0 | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_async_iter(db, intfields_data): | ||
| counter = 0 | ||
|
|
@@ -1156,3 +1188,72 @@ async def test_union_with_annotate_raises(db): | |
|
|
||
| with pytest.raises(ParamsError, match="Union queries do not support annotations"): | ||
| await qs1.union(qs2) | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_update_limit_order_by_with_join(db): | ||
| old_cap_val = Event._meta.db.capabilities.support_update_limit_order_by | ||
| object.__setattr__(Event._meta.db.capabilities, "_mutable", True) | ||
| Event._meta.db.capabilities.support_update_limit_order_by = True | ||
| try: | ||
| t1 = await Tournament.create(name="T1") | ||
| e1 = await Event.create(name="E1", tournament=t1) | ||
| e2 = await Event.create(name="E2", tournament=t1) | ||
|
|
||
| updated = ( | ||
| await Event.filter(tournament__name="T1") | ||
| .order_by("event_id") | ||
| .limit(1) | ||
| .update(name="E1_updated") | ||
| ) | ||
| assert updated == 1 | ||
|
|
||
| await e1.refresh_from_db() | ||
| await e2.refresh_from_db() | ||
| assert e1.name == "E1_updated" | ||
| assert e2.name == "E2" | ||
| finally: | ||
| Event._meta.db.capabilities.support_update_limit_order_by = old_cap_val | ||
| object.__setattr__(Event._meta.db.capabilities, "_mutable", False) | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_delete_limit_order_by_with_join(db): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are this test and the one above related to this PR? If not, please move them to a separate PR. If they are related, please use a |
||
| old_cap_val = Event._meta.db.capabilities.support_update_limit_order_by | ||
| object.__setattr__(Event._meta.db.capabilities, "_mutable", True) | ||
| Event._meta.db.capabilities.support_update_limit_order_by = True | ||
| try: | ||
| t1 = await Tournament.create(name="T1") | ||
| await Event.create(name="E1", tournament=t1) | ||
| await Event.create(name="E2", tournament=t1) | ||
|
|
||
| deleted = await Event.filter(tournament__name="T1").order_by("event_id").limit(1).delete() | ||
| assert deleted == 1 | ||
|
|
||
| count = await Event.all().count() | ||
| assert count == 1 | ||
| finally: | ||
| Event._meta.db.capabilities.support_update_limit_order_by = old_cap_val | ||
| object.__setattr__(Event._meta.db.capabilities, "_mutable", False) | ||
|
|
||
|
|
||
| def test_update_query_postgres_dialect_coverage(db): | ||
| from tortoise.backends.base.client import Capabilities | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't need to be inside a function — please move it to the top of the file. |
||
|
|
||
| q = Event.filter(tournament__name="T1").limit(1).update(name="E1_updated") | ||
| q.capabilities = Capabilities("postgres", support_update_limit_order_by=False) | ||
| sql = q.sql() | ||
| assert "IN (SELECT " in sql | ||
| assert '"_t"' not in sql | ||
| assert "`_t`" not in sql | ||
|
|
||
|
|
||
| def test_delete_query_postgres_dialect_coverage(db): | ||
| from tortoise.backends.base.client import Capabilities | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also move it to the top. |
||
|
|
||
| q = Event.filter(tournament__name="T1").delete() | ||
| q.capabilities = Capabilities("postgres", support_update_limit_order_by=False) | ||
| sql = q.sql() | ||
| assert "IN (SELECT " in sql | ||
| assert '"_t"' not in sql | ||
| assert "`_t`" not in sql | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this, as it is unrelated to this PR.