|
1 | 1 | from unittest.mock import patch |
2 | 2 |
|
3 | | -from django.db import connection |
| 3 | +from django.db import NotSupportedError, connection |
4 | 4 | from django.db.models import ( |
5 | 5 | Case, |
6 | 6 | F, |
|
14 | 14 | ) |
15 | 15 | from django.db.models.functions import Cast |
16 | 16 | from django.db.models.lookups import Exact |
17 | | -from django.test import TestCase, skipUnlessDBFeature |
| 17 | +from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature |
18 | 18 |
|
19 | 19 | from .models import Comment, Tenant, User |
20 | 20 |
|
@@ -492,6 +492,39 @@ def test_outer_ref_pk(self): |
492 | 492 | queryset = Comment.objects.filter(**{f"id{lookup}": subquery}) |
493 | 493 | self.assertEqual(queryset.count(), expected_count) |
494 | 494 |
|
| 495 | + def test_outer_ref_pk_filter_on_pk_exact(self): |
| 496 | + subquery = Subquery(User.objects.filter(pk=OuterRef("pk")).values("pk")[:1]) |
| 497 | + qs = Comment.objects.filter(pk=subquery) |
| 498 | + self.assertEqual(qs.count(), 2) |
| 499 | + |
| 500 | + @skipUnlessDBFeature("supports_tuple_comparison_against_subquery") |
| 501 | + def test_outer_ref_pk_filter_on_pk_comparison(self): |
| 502 | + subquery = Subquery(User.objects.filter(pk=OuterRef("pk")).values("pk")[:1]) |
| 503 | + tests = [ |
| 504 | + ("gt", 0), |
| 505 | + ("gte", 2), |
| 506 | + ("lt", 0), |
| 507 | + ("lte", 2), |
| 508 | + ] |
| 509 | + for lookup, expected_count in tests: |
| 510 | + with self.subTest(f"pk__{lookup}"): |
| 511 | + qs = Comment.objects.filter(**{f"pk__{lookup}": subquery}) |
| 512 | + self.assertEqual(qs.count(), expected_count) |
| 513 | + |
| 514 | + @skipIfDBFeature("supports_tuple_comparison_against_subquery") |
| 515 | + def test_outer_ref_pk_filter_on_pk_comparison_unsupported(self): |
| 516 | + subquery = Subquery(User.objects.filter(pk=OuterRef("pk")).values("pk")[:1]) |
| 517 | + tests = ["gt", "gte", "lt", "lte"] |
| 518 | + for lookup in tests: |
| 519 | + with self.subTest(f"pk__{lookup}"): |
| 520 | + qs = Comment.objects.filter(**{f"pk__{lookup}": subquery}) |
| 521 | + with self.assertRaisesMessage( |
| 522 | + NotSupportedError, |
| 523 | + f'"{lookup}" cannot be used to target composite fields ' |
| 524 | + "through subqueries on this backend", |
| 525 | + ): |
| 526 | + qs.count() |
| 527 | + |
495 | 528 | def test_unsupported_rhs(self): |
496 | 529 | pk = Exact(F("tenant_id"), 1) |
497 | 530 | msg = ( |
@@ -561,7 +594,11 @@ def test_filter_by_tuple_containing_expression(self): |
561 | 594 | @skipUnlessDBFeature("supports_tuple_lookups") |
562 | 595 | class CompositePKFilterTupleLookupFallbackTests(CompositePKFilterTests): |
563 | 596 | def setUp(self): |
564 | | - feature_patch = patch.object( |
| 597 | + feature_patch_1 = patch.object( |
565 | 598 | connection.features, "supports_tuple_lookups", False |
566 | 599 | ) |
567 | | - self.enterContext(feature_patch) |
| 600 | + feature_patch_2 = patch.object( |
| 601 | + connection.features, "supports_tuple_comparison_against_subquery", False |
| 602 | + ) |
| 603 | + self.enterContext(feature_patch_1) |
| 604 | + self.enterContext(feature_patch_2) |
0 commit comments