Fixed #24254 -- Fixed queries using the __in lookup with querysets using distinct() and order_by().
Thanks Tim for the review.
This commit is contained in:
parent
a9874d48b1
commit
4acae21846
|
@ -523,6 +523,31 @@ class SQLCompiler:
|
||||||
if for_update_part and not self.connection.features.for_update_after_from:
|
if for_update_part and not self.connection.features.for_update_after_from:
|
||||||
result.append(for_update_part)
|
result.append(for_update_part)
|
||||||
|
|
||||||
|
if self.query.subquery and extra_select:
|
||||||
|
# If the query is used as a subquery, the extra selects would
|
||||||
|
# result in more columns than the left-hand side expression is
|
||||||
|
# expecting. This can happen when a subquery uses a combination
|
||||||
|
# of order_by() and distinct(), forcing the ordering expressions
|
||||||
|
# to be selected as well. Wrap the query in another subquery
|
||||||
|
# to exclude extraneous selects.
|
||||||
|
sub_selects = []
|
||||||
|
sub_params = []
|
||||||
|
for select, _, alias in self.select:
|
||||||
|
if alias:
|
||||||
|
sub_selects.append("%s.%s" % (
|
||||||
|
self.connection.ops.quote_name('subquery'),
|
||||||
|
self.connection.ops.quote_name(alias),
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
select_clone = select.relabeled_clone({select.alias: 'subquery'})
|
||||||
|
subselect, subparams = select_clone.as_sql(self, self.connection)
|
||||||
|
sub_selects.append(subselect)
|
||||||
|
sub_params.extend(subparams)
|
||||||
|
return 'SELECT %s FROM (%s) AS subquery' % (
|
||||||
|
', '.join(sub_selects),
|
||||||
|
' '.join(result),
|
||||||
|
), sub_params + params
|
||||||
|
|
||||||
return ' '.join(result), tuple(params)
|
return ' '.join(result), tuple(params)
|
||||||
finally:
|
finally:
|
||||||
# Finally do cleanup - get rid of the joins we created above.
|
# Finally do cleanup - get rid of the joins we created above.
|
||||||
|
|
|
@ -2005,10 +2005,10 @@ class QuerysetOrderedTests(unittest.TestCase):
|
||||||
class SubqueryTests(TestCase):
|
class SubqueryTests(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
DumbCategory.objects.create(id=1)
|
NamedCategory.objects.create(id=1, name='first')
|
||||||
DumbCategory.objects.create(id=2)
|
NamedCategory.objects.create(id=2, name='second')
|
||||||
DumbCategory.objects.create(id=3)
|
NamedCategory.objects.create(id=3, name='third')
|
||||||
DumbCategory.objects.create(id=4)
|
NamedCategory.objects.create(id=4, name='fourth')
|
||||||
|
|
||||||
def test_ordered_subselect(self):
|
def test_ordered_subselect(self):
|
||||||
"Subselects honor any manual ordering"
|
"Subselects honor any manual ordering"
|
||||||
|
@ -2064,6 +2064,28 @@ class SubqueryTests(TestCase):
|
||||||
DumbCategory.objects.filter(id__in=DumbCategory.objects.order_by('-id')[1:]).delete()
|
DumbCategory.objects.filter(id__in=DumbCategory.objects.order_by('-id')[1:]).delete()
|
||||||
self.assertEqual(set(DumbCategory.objects.values_list('id', flat=True)), {3})
|
self.assertEqual(set(DumbCategory.objects.values_list('id', flat=True)), {3})
|
||||||
|
|
||||||
|
def test_distinct_ordered_sliced_subquery(self):
|
||||||
|
# Implicit values('id').
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
NamedCategory.objects.filter(
|
||||||
|
id__in=NamedCategory.objects.distinct().order_by('name')[0:2],
|
||||||
|
).order_by('name').values_list('name', flat=True), ['first', 'fourth']
|
||||||
|
)
|
||||||
|
# Explicit values('id').
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
NamedCategory.objects.filter(
|
||||||
|
id__in=NamedCategory.objects.distinct().order_by('-name').values('id')[0:2],
|
||||||
|
).order_by('name').values_list('name', flat=True), ['second', 'third']
|
||||||
|
)
|
||||||
|
# Annotated value.
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
DumbCategory.objects.filter(
|
||||||
|
id__in=DumbCategory.objects.annotate(
|
||||||
|
double_id=F('id') * 2
|
||||||
|
).order_by('id').distinct().values('double_id')[0:2],
|
||||||
|
).order_by('id').values_list('id', flat=True), [2, 4]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CloneTests(TestCase):
|
class CloneTests(TestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue