diff options
| author | Simon Charette <charette.s@gmail.com> | 2024-12-22 23:00:04 -0500 |
|---|---|---|
| committer | Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> | 2025-02-06 16:57:44 +0100 |
| commit | 089deb82b9ac2d002af36fd36f288368cdac4b53 (patch) | |
| tree | 5a9952ec4a9fa0ee73b233bc5551ac645543ea40 /tests | |
| parent | b13b8684a04d0bc1081104c5973c62c27dc673b0 (diff) | |
Fixed #36025 -- Fixed re-aliasing of iterable (in/range) lookups rhs.
In order for Expression.relabeled_clone to work appropriately its
get_source_expressions method must return all resolvable which wasn't the case
for Lookup when its right-hand-side is "direct" (not a compilable).
While refs #22288 added support for non-literals iterable right-hand-side
lookups it predated the subclassing of Lookup(Expression) refs #27021 which
could have been an opportunity to ensure right-hand-sides are always resolvable
(ValueList and ExpressionList).
Addressing all edge case with non-resolvable right-hand-sides would require
a significant refactor and deprecation of some parts of the Lookup interface so
this patch only focuses on FieldGetDbPrepValueIterableMixin (In and Range
lookups) by making sure that a right-hand-side containing resolvables are dealt
with appropriately during the resolving phase.
Thanks Aashay Amballi for the report.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/expressions/tests.py | 17 | ||||
| -rw-r--r-- | tests/model_fields/test_jsonfield.py | 3 |
2 files changed, 19 insertions, 1 deletions
diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py index d36107b358..cfa33b6f45 100644 --- a/tests/expressions/tests.py +++ b/tests/expressions/tests.py @@ -1276,6 +1276,23 @@ class IterableLookupInnerExpressionsTests(TestCase): queryset = Result.objects.filter(**{lookup: within_experiment_time}) self.assertSequenceEqual(queryset, [r1]) + def test_relabeled_clone_rhs(self): + Number.objects.bulk_create([Number(integer=1), Number(integer=2)]) + self.assertIs( + Number.objects.filter( + # Ensure iterable of expressions are properly re-labelled on + # subquery pushdown. If the inner query __range right-hand-side + # members are not relabelled they will point at the outer query + # alias and this test will fail. + Exists( + Number.objects.exclude(pk=OuterRef("pk")).filter( + integer__range=(F("integer"), F("integer")) + ) + ) + ).exists(), + True, + ) + class FTests(SimpleTestCase): def test_deepcopy(self): diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py index 09f95ce69f..5a9cf9ad7a 100644 --- a/tests/model_fields/test_jsonfield.py +++ b/tests/model_fields/test_jsonfield.py @@ -13,6 +13,7 @@ from django.db import ( OperationalError, connection, models, + transaction, ) from django.db.models import ( Count, @@ -974,7 +975,7 @@ class TestQuerying(TestCase): ("value__i__in", [False, "foo"], [self.objs[4]]), ] for lookup, value, expected in tests: - with self.subTest(lookup=lookup, value=value): + with self.subTest(lookup=lookup, value=value), transaction.atomic(): self.assertCountEqual( NullableJSONModel.objects.filter(**{lookup: value}), expected, |
