mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #29538 -- Fixed crash of ordering by related fields when Meta.ordering contains expressions.
Thanks Simon Charette for the review.
This commit is contained in:
parent
34e2148fc7
commit
2798c937de
@ -402,6 +402,18 @@ class BaseExpression:
|
||||
def copy(self):
|
||||
return copy.copy(self)
|
||||
|
||||
def prefix_references(self, prefix):
|
||||
clone = self.copy()
|
||||
clone.set_source_expressions(
|
||||
[
|
||||
F(f"{prefix}{expr.name}")
|
||||
if isinstance(expr, F)
|
||||
else expr.prefix_references(prefix)
|
||||
for expr in self.get_source_expressions()
|
||||
]
|
||||
)
|
||||
return clone
|
||||
|
||||
def get_group_by_cols(self, alias=None):
|
||||
if not self.contains_aggregate:
|
||||
return [self]
|
||||
|
@ -912,10 +912,15 @@ class SQLCompiler:
|
||||
):
|
||||
item = item.desc() if descending else item.asc()
|
||||
if isinstance(item, OrderBy):
|
||||
results.append((item, False))
|
||||
results.append(
|
||||
(item.prefix_references(f"{name}{LOOKUP_SEP}"), False)
|
||||
)
|
||||
continue
|
||||
results.extend(
|
||||
self.find_ordering_name(item, opts, alias, order, already_seen)
|
||||
(expr.prefix_references(f"{name}{LOOKUP_SEP}"), is_ref)
|
||||
for expr, is_ref in self.find_ordering_name(
|
||||
item, opts, alias, order, already_seen
|
||||
)
|
||||
)
|
||||
return results
|
||||
targets, alias, _ = self.query.trim_joins(targets, joins, path)
|
||||
|
@ -62,3 +62,21 @@ class Reference(models.Model):
|
||||
|
||||
class Meta:
|
||||
ordering = ("article",)
|
||||
|
||||
|
||||
class OrderedByExpression(models.Model):
|
||||
name = models.CharField(max_length=30)
|
||||
|
||||
class Meta:
|
||||
ordering = [models.functions.Lower("name")]
|
||||
|
||||
|
||||
class OrderedByExpressionChild(models.Model):
|
||||
parent = models.ForeignKey(OrderedByExpression, models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
ordering = ["parent"]
|
||||
|
||||
|
||||
class OrderedByExpressionGrandChild(models.Model):
|
||||
parent = models.ForeignKey(OrderedByExpressionChild, models.CASCADE)
|
||||
|
@ -14,7 +14,16 @@ from django.db.models import (
|
||||
from django.db.models.functions import Upper
|
||||
from django.test import TestCase
|
||||
|
||||
from .models import Article, Author, ChildArticle, OrderedByFArticle, Reference
|
||||
from .models import (
|
||||
Article,
|
||||
Author,
|
||||
ChildArticle,
|
||||
OrderedByExpression,
|
||||
OrderedByExpressionChild,
|
||||
OrderedByExpressionGrandChild,
|
||||
OrderedByFArticle,
|
||||
Reference,
|
||||
)
|
||||
|
||||
|
||||
class OrderingTests(TestCase):
|
||||
@ -550,3 +559,30 @@ class OrderingTests(TestCase):
|
||||
{"author": self.author_2.pk, "count": 1},
|
||||
],
|
||||
)
|
||||
|
||||
def test_order_by_parent_fk_with_expression_in_default_ordering(self):
|
||||
p3 = OrderedByExpression.objects.create(name="oBJ 3")
|
||||
p2 = OrderedByExpression.objects.create(name="OBJ 2")
|
||||
p1 = OrderedByExpression.objects.create(name="obj 1")
|
||||
c3 = OrderedByExpressionChild.objects.create(parent=p3)
|
||||
c2 = OrderedByExpressionChild.objects.create(parent=p2)
|
||||
c1 = OrderedByExpressionChild.objects.create(parent=p1)
|
||||
self.assertSequenceEqual(
|
||||
OrderedByExpressionChild.objects.order_by("parent"),
|
||||
[c1, c2, c3],
|
||||
)
|
||||
|
||||
def test_order_by_grandparent_fk_with_expression_in_default_ordering(self):
|
||||
p3 = OrderedByExpression.objects.create(name="oBJ 3")
|
||||
p2 = OrderedByExpression.objects.create(name="OBJ 2")
|
||||
p1 = OrderedByExpression.objects.create(name="obj 1")
|
||||
c3 = OrderedByExpressionChild.objects.create(parent=p3)
|
||||
c2 = OrderedByExpressionChild.objects.create(parent=p2)
|
||||
c1 = OrderedByExpressionChild.objects.create(parent=p1)
|
||||
g3 = OrderedByExpressionGrandChild.objects.create(parent=c3)
|
||||
g2 = OrderedByExpressionGrandChild.objects.create(parent=c2)
|
||||
g1 = OrderedByExpressionGrandChild.objects.create(parent=c1)
|
||||
self.assertSequenceEqual(
|
||||
OrderedByExpressionGrandChild.objects.order_by("parent"),
|
||||
[g1, g2, g3],
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user