diff options
| author | willzhao <gnomeek@outlook.com> | 2023-08-31 07:51:44 +0000 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-09-01 10:44:20 +0200 |
| commit | 9cc0d7f7f85cecc3ad15bbc471fe6a08e4f515b6 (patch) | |
| tree | b50db16197265db37269d94ec68d8690ff58c57d | |
| parent | 9c6879284315d5119942355c340c3e48f6c65882 (diff) | |
Fixed #34803 -- Fixed queryset crash when filtering againts deeply nested OuterRef annotations.
Thanks Pierre-Nicolas Rigal for the report.
Regression in c67ea79aa981ae82595d89f8018a41fcd842e7c9.
| -rw-r--r-- | AUTHORS | 1 | ||||
| -rw-r--r-- | django/db/models/expressions.py | 1 | ||||
| -rw-r--r-- | docs/releases/4.2.5.txt | 3 | ||||
| -rw-r--r-- | tests/expressions/models.py | 4 | ||||
| -rw-r--r-- | tests/expressions/tests.py | 30 |
5 files changed, 39 insertions, 0 deletions
@@ -1033,6 +1033,7 @@ answer newbie questions, and generally made Django that much better: Will Ayd <william.ayd@icloud.com> William Schwartz <wkschwartz@gmail.com> Will Hardy <django@willhardy.com.au> + Will Zhao <www.gnomeek@gmail.com> Wilson Miner <wminer@gmail.com> Wim Glenn <hey@wimglenn.com> wojtek diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index ac3ddfbc9d..4ea179ecde 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -885,6 +885,7 @@ class ResolvedOuterRef(F): class OuterRef(F): contains_aggregate = False + contains_over_clause = False def resolve_expression(self, *args, **kwargs): if isinstance(self.name, self.__class__): diff --git a/docs/releases/4.2.5.txt b/docs/releases/4.2.5.txt index fe216cadb3..d88ece91e6 100644 --- a/docs/releases/4.2.5.txt +++ b/docs/releases/4.2.5.txt @@ -21,3 +21,6 @@ Bugfixes * Fixed a regression in Django 4.2.2 that caused an unnecessary selection of a non-nullable ``ManyToManyField`` without a natural key during serialization (:ticket:`34779`). + +* Fixed a regression in Django 4.2 that caused a crash of a queryset when + filtering against deeply nested ``OuterRef()`` annotations (:ticket:`34803`). diff --git a/tests/expressions/models.py b/tests/expressions/models.py index 35985dc5f0..0a8a0a6584 100644 --- a/tests/expressions/models.py +++ b/tests/expressions/models.py @@ -8,6 +8,9 @@ from django.db import models class Manager(models.Model): name = models.CharField(max_length=50) + secretary = models.ForeignKey( + "Employee", models.CASCADE, null=True, related_name="managers" + ) class Employee(models.Model): @@ -15,6 +18,7 @@ class Employee(models.Model): lastname = models.CharField(max_length=50) salary = models.IntegerField(blank=True, null=True) manager = models.ForeignKey(Manager, models.CASCADE, null=True) + based_in_eu = models.BooleanField(default=False) def __str__(self): return "%s %s" % (self.firstname, self.lastname) diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py index 9ba354f9f4..4bd46762e1 100644 --- a/tests/expressions/tests.py +++ b/tests/expressions/tests.py @@ -870,6 +870,36 @@ class BasicExpressionsTests(TestCase): ).filter(ceo_company__isnull=False) self.assertEqual(qs.get().ceo_company, "Test GmbH") + def test_annotation_with_deeply_nested_outerref(self): + bob = Employee.objects.create(firstname="Bob", based_in_eu=True) + self.max.manager = Manager.objects.create(name="Rock", secretary=bob) + self.max.save() + qs = Employee.objects.filter( + Exists( + Manager.objects.filter( + Exists( + Employee.objects.filter( + pk=OuterRef("secretary__pk"), + ) + .annotate( + secretary_based_in_eu=OuterRef(OuterRef("based_in_eu")) + ) + .filter( + Exists( + Company.objects.filter( + # Inner OuterRef refers to an outer + # OuterRef (not ResolvedOuterRef). + based_in_eu=OuterRef("secretary_based_in_eu") + ) + ) + ) + ), + secretary__pk=OuterRef("pk"), + ) + ) + ) + self.assertEqual(qs.get(), bob) + def test_pickle_expression(self): expr = Value(1) expr.convert_value # populate cached property |
