0
0
mirror of https://github.com/django/django.git synced 2024-11-24 11:48:10 +01:00

Fixed #34803 -- Fixed queryset crash when filtering againts deeply nested OuterRef annotations.

Thanks Pierre-Nicolas Rigal for the report.

Regression in c67ea79aa9.
This commit is contained in:
willzhao 2023-08-31 07:51:44 +00:00 committed by Mariusz Felisiak
parent 9c68792843
commit 9cc0d7f7f8
5 changed files with 39 additions and 0 deletions

View File

@ -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

View File

@ -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__):

View File

@ -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`).

View File

@ -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)

View File

@ -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