1
0
mirror of https://github.com/django/django.git synced 2025-03-31 11:37:06 +00:00

Fixed #34533 -- OuterRef not resolved as part of ORDER BY clause

This commit is contained in:
Ayush khatri 2024-12-02 23:59:52 +05:30
parent 58cc91275a
commit dbc30234be
3 changed files with 91 additions and 1 deletions

View File

@ -2779,3 +2779,31 @@ class JoinPromoter:
query.promote_joins(to_promote)
query.demote_joins(to_demote)
return to_demote
def resolve_order_by_expressions(self, order_by_expressions):
"""
Resolve expressions in the order_by clause containing OuterRef by cloning
and resolving them. Other expressions are appended as is.
"""
resolved_expressions = []
for expr in order_by_expressions:
if (
hasattr(expr, "contains_outer_reference")
and expr.contains_outer_reference()
):
clone = expr.clone()
clone.outer_query = self.outer_query
resolved_expressions.append(clone.resolve_expression(self))
else:
resolved_expressions.append(expr)
return resolved_expressions
def get_compiler(self, *args, **kwargs):
"""
Override get_compiler to resolve order_by expressions containing OuterRef.
"""
if self.order_by:
self.order_by = self.resolve_order_by_expressions(self.order_by)
return super().get_compiler(*args, **kwargs)

View File

@ -32,7 +32,7 @@ class RemoteEmployee(Employee):
class Company(models.Model):
name = models.CharField(max_length=100)
num_employees = models.PositiveIntegerField()
num_chairs = models.PositiveIntegerField()
num_chairs = models.PositiveIntegerField(default=0)
ceo = models.ForeignKey(
Employee,
models.CASCADE,
@ -122,3 +122,10 @@ class JSONFieldModel(models.Model):
class Meta:
required_db_features = {"supports_json_field"}
class NamedCategory(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
def __str__(self):
return self.name

View File

@ -6,6 +6,7 @@ from collections import namedtuple
from copy import deepcopy
from decimal import Decimal
from unittest import mock
from .models import NamedCategory
from django.core.exceptions import FieldError
from django.db import DatabaseError, NotSupportedError, connection
@ -2849,3 +2850,57 @@ class OrderByTests(SimpleTestCase):
F("field").asc(nulls_first=False)
with self.assertRaisesMessage(ValueError, msg):
F("field").desc(nulls_last=False)
class OuterRefOrderByTestCase(TestCase):
@classmethod
def setUpTestData(cls):
cls.ceo = Employee.objects.create(
firstname="John", lastname="Doe", salary=100000
)
cls.gmbh = Company.objects.create(
name="GmbH",
num_employees=50,
ceo=cls.ceo,
point_of_contact=cls.ceo,
based_in_eu=True,
)
cls.foobar_ltd = Company.objects.create(
name="Foobar Ltd",
num_employees=100,
ceo=cls.ceo,
point_of_contact=cls.ceo,
based_in_eu=False,
)
def test_order_by_with_outerref(self):
inner = Company.objects.filter(
num_employees__lt=OuterRef("num_employees")
).order_by("num_employees")
qs = Company.objects.annotate(next_bigger=Subquery(inner.values("pk")[:1]))
foobar_ltd = qs.get(pk=self.foobar_ltd.pk)
self.assertIsNotNone(foobar_ltd.next_bigger)
self.assertEqual(foobar_ltd.next_bigger, self.gmbh.pk)
class SubqueryTests(TestCase):
def test_outer_ref_order_by(self):
NamedCategory.objects.create(id=1, name="first")
NamedCategory.objects.create(id=4, name="fourth")
NamedCategory.objects.create(id=2, name="second")
NamedCategory.objects.create(id=3, name="third")
outer_query = NamedCategory.objects.all()
subquery = (
NamedCategory.objects.filter(id=OuterRef("id"))
.order_by("name")
.values("name")
)
values = outer_query.annotate(sorted_name=Subquery(subquery)).order_by(
"sorted_name"
)
sorted_names = list(values.values_list("sorted_name", flat=True))
self.assertListEqual(sorted_names, ["first", "fourth", "second", "third"])