summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/models/sql/compiler.py7
-rw-r--r--tests/select_for_update/tests.py9
2 files changed, 14 insertions, 2 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 1319b288aa..51c3d6e661 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -476,8 +476,11 @@ class SQLCompiler(object):
Used when nesting this query inside another.
"""
obj = self.query.clone()
- if obj.low_mark == 0 and obj.high_mark is None and not self.query.distinct_fields:
- # If there is no slicing in use, then we can safely drop all ordering
+ # It's safe to drop ordering if the queryset isn't using slicing,
+ # distinct(*fields) or select_for_update().
+ if (obj.low_mark == 0 and obj.high_mark is None and
+ not self.query.distinct_fields and
+ not self.query.select_for_update):
obj.clear_ordering(True)
nested_sql = obj.get_compiler(connection=self.connection).as_sql(subquery=True)
if nested_sql == ('', ()):
diff --git a/tests/select_for_update/tests.py b/tests/select_for_update/tests.py
index e6e1155ee2..4c30ff7179 100644
--- a/tests/select_for_update/tests.py
+++ b/tests/select_for_update/tests.py
@@ -300,3 +300,12 @@ class SelectForUpdateTests(TransactionTestCase):
def test_nowait_and_skip_locked(self):
with self.assertRaisesMessage(ValueError, 'The nowait option cannot be used with skip_locked.'):
Person.objects.select_for_update(nowait=True, skip_locked=True)
+
+ def test_ordered_select_for_update(self):
+ """
+ Subqueries should respect ordering as an ORDER BY clause may be useful
+ to specify a row locking order to prevent deadlocks (#27193).
+ """
+ with transaction.atomic():
+ qs = Person.objects.filter(id__in=Person.objects.order_by('-id').select_for_update())
+ self.assertIn('ORDER BY', str(qs.query))