mirror of
https://github.com/django/django.git
synced 2025-06-05 11:39:13 +00:00
Fixed #34533 -- OuterRef not resolved as part of ORDER BY clause
This commit is contained in:
parent
58cc91275a
commit
fd3cd5de59
@ -2779,3 +2779,31 @@ class JoinPromoter:
|
|||||||
query.promote_joins(to_promote)
|
query.promote_joins(to_promote)
|
||||||
query.demote_joins(to_demote)
|
query.demote_joins(to_demote)
|
||||||
return 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)
|
||||||
|
@ -32,7 +32,7 @@ class RemoteEmployee(Employee):
|
|||||||
class Company(models.Model):
|
class Company(models.Model):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
num_employees = models.PositiveIntegerField()
|
num_employees = models.PositiveIntegerField()
|
||||||
num_chairs = models.PositiveIntegerField()
|
num_chairs = models.PositiveIntegerField(default=0)
|
||||||
ceo = models.ForeignKey(
|
ceo = models.ForeignKey(
|
||||||
Employee,
|
Employee,
|
||||||
models.CASCADE,
|
models.CASCADE,
|
||||||
|
@ -2849,3 +2849,36 @@ class OrderByTests(SimpleTestCase):
|
|||||||
F("field").asc(nulls_first=False)
|
F("field").asc(nulls_first=False)
|
||||||
with self.assertRaisesMessage(ValueError, msg):
|
with self.assertRaisesMessage(ValueError, msg):
|
||||||
F("field").desc(nulls_last=False)
|
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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user