summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwillzhao <gnomeek@outlook.com>2023-08-31 07:51:44 +0000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-09-01 11:25:00 +0200
commitacfb42752259c3f920ffd20d6eef83b3c6f75cf7 (patch)
tree552ba3871fcacd330d58a91c91a17fddaa85bf46
parent55a0b9c32ebae957b95a9a55846692837e2ff39b (diff)
[4.2.x] Fixed #34803 -- Fixed queryset crash when filtering againts deeply nested OuterRef annotations.
Thanks Pierre-Nicolas Rigal for the report. Regression in c67ea79aa981ae82595d89f8018a41fcd842e7c9. Backport of 9cc0d7f7f85cecc3ad15bbc471fe6a08e4f515b6 from main
-rw-r--r--AUTHORS1
-rw-r--r--django/db/models/expressions.py1
-rw-r--r--docs/releases/4.2.5.txt3
-rw-r--r--tests/expressions/models.py4
-rw-r--r--tests/expressions/tests.py30
5 files changed, 39 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
index af30e8d78e..f8afd7e88b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1021,6 +1021,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 c6443892e2..cc78ac8773 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -879,6 +879,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 7db6013819..a928b76bab 100644
--- a/tests/expressions/tests.py
+++ b/tests/expressions/tests.py
@@ -871,6 +871,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