mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Fixed qs.order_by() join promotion for already existing joins
When order_by causes new joins to be added to the query, the joins must be LEFT OUTER joins for nullable relations, otherwise the order_by could cause the results to be altered. This commit fixes the logic to only promote new joins, previously all joins in the order_by lookup path were promoted. Thanks to Bruno Desthuilliers for spotting this corner case.
This commit is contained in:
@@ -19,7 +19,8 @@ from .models import (Annotation, Article, Author, Celebrity, Child, Cover,
|
||||
ManagedModel, Member, NamedCategory, Note, Number, Plaything, PointerA,
|
||||
Ranking, Related, Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten,
|
||||
Node, ObjectA, ObjectB, ObjectC, CategoryItem, SimpleCategory,
|
||||
SpecialCategory, OneToOneCategory, NullableName, ProxyCategory)
|
||||
SpecialCategory, OneToOneCategory, NullableName, ProxyCategory,
|
||||
SingleObject, RelatedObject)
|
||||
|
||||
|
||||
class BaseQuerysetTest(TestCase):
|
||||
@@ -1321,12 +1322,33 @@ class NullableRelOrderingTests(TestCase):
|
||||
def test_ticket10028(self):
|
||||
# Ordering by model related to nullable relations(!) should use outer
|
||||
# joins, so that all results are included.
|
||||
_ = Plaything.objects.create(name="p1")
|
||||
Plaything.objects.create(name="p1")
|
||||
self.assertQuerysetEqual(
|
||||
Plaything.objects.all(),
|
||||
['<Plaything: p1>']
|
||||
)
|
||||
|
||||
def test_join_already_in_query(self):
|
||||
# Ordering by model related to nullable relations should not change
|
||||
# the join type of already existing joins.
|
||||
Plaything.objects.create(name="p1")
|
||||
s = SingleObject.objects.create(name='s')
|
||||
r = RelatedObject.objects.create(single=s)
|
||||
Plaything.objects.create(name="p2", others=r)
|
||||
qs = Plaything.objects.all().filter(others__isnull=False).order_by('pk')
|
||||
self.assertTrue('INNER' in str(qs.query))
|
||||
qs = qs.order_by('others__single__name')
|
||||
# The ordering by others__single__pk will add one new join (to single)
|
||||
# and that join must be LEFT join. The already existing join to related
|
||||
# objects must be kept INNER. So, we have both a INNER and a LEFT join
|
||||
# in the query.
|
||||
self.assertTrue('LEFT' in str(qs.query))
|
||||
self.assertTrue('INNER' in str(qs.query))
|
||||
self.assertQuerysetEqual(
|
||||
qs,
|
||||
['<Plaything: p2>']
|
||||
)
|
||||
|
||||
|
||||
class DisjunctiveFilterTests(TestCase):
|
||||
def setUp(self):
|
||||
|
||||
Reference in New Issue
Block a user