summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Michel <mail@raphaelmichel.de>2017-11-26 17:32:17 +0100
committerTim Graham <timograham@gmail.com>2017-11-27 11:40:09 -0500
commit899999db4293d40613626833860de28e8ccdd413 (patch)
tree90a6ce823ab5e56e87ad246af3262708fbd3126f
parenta09e974688e283019df32c35c6d7c217d1d16a8e (diff)
[1.11.x] Fixed #28848 -- Fixed SQLite/MySQL crash when ordering by a filtered subquery that uses nulls_first/nulls_last.
Backport of 616f468760e4984915bb2ccca6b9eb3d80ddadb0 from master
-rw-r--r--django/db/models/expressions.py1
-rw-r--r--docs/releases/1.11.8.txt3
-rw-r--r--tests/ordering/tests.py23
3 files changed, 26 insertions, 1 deletions
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 2db832e1eb..e7084ebfc6 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -1063,6 +1063,7 @@ class OrderBy(BaseExpression):
}
placeholders.update(extra_context)
template = template or self.template
+ params *= template.count('%(expression)s')
return (template % placeholders).rstrip(), params
def as_sqlite(self, compiler, connection):
diff --git a/docs/releases/1.11.8.txt b/docs/releases/1.11.8.txt
index 89b6e5ed52..6f744a6886 100644
--- a/docs/releases/1.11.8.txt
+++ b/docs/releases/1.11.8.txt
@@ -21,3 +21,6 @@ Bugfixes
* Made ``QuerySet.iterator()`` use server-side cursors on PostgreSQL after
``values()`` and ``values_list()`` (:ticket:`28817`).
+
+* Fixed crash on SQLite and MySQL when ordering by a filtered subquery that
+ uses ``nulls_first`` or ``nulls_last`` (:ticket:`28848`).
diff --git a/tests/ordering/tests.py b/tests/ordering/tests.py
index 62ce558a93..d93c511e61 100644
--- a/tests/ordering/tests.py
+++ b/tests/ordering/tests.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from datetime import datetime
from operator import attrgetter
-from django.db.models import F
+from django.db.models import DateTimeField, F, Max, OuterRef, Subquery
from django.db.models.functions import Upper
from django.test import TestCase
@@ -140,6 +140,27 @@ class OrderingTests(TestCase):
[self.a1, self.a2, self.a4, self.a3],
)
+ def test_orders_nulls_first_on_filtered_subquery(self):
+ Article.objects.filter(headline='Article 1').update(author=self.author_1)
+ Article.objects.filter(headline='Article 2').update(author=self.author_1)
+ Article.objects.filter(headline='Article 4').update(author=self.author_2)
+ Author.objects.filter(name__isnull=True).delete()
+ author_3 = Author.objects.create(name='Name 3')
+ article_subquery = Article.objects.filter(
+ author=OuterRef('pk'),
+ headline__icontains='Article',
+ ).order_by().values('author').annotate(
+ last_date=Max('pub_date'),
+ ).values('last_date')
+ self.assertQuerysetEqualReversible(
+ Author.objects.annotate(
+ last_date=Subquery(article_subquery, output_field=DateTimeField())
+ ).order_by(
+ F('last_date').asc(nulls_first=True)
+ ).distinct(),
+ [author_3, self.author_1, self.author_2],
+ )
+
def test_stop_slicing(self):
"""
Use the 'stop' part of slicing notation to limit the results.