From 1d50f12929f8f2d424f0e7cc6b1f693f590f71a2 Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Tue, 18 Aug 2026 12:37:10 +0200 Subject: [PATCH] Fixed #37258, Refs #36644 -- Documented error when default ordering fields are missing in combined queries. Thank you Adam Johnson for the report. --- docs/releases/6.1.txt | 7 +++++++ tests/queries/test_qs_combinators.py | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/docs/releases/6.1.txt b/docs/releases/6.1.txt index 3d7700bfc93e..eee60237f31d 100644 --- a/docs/releases/6.1.txt +++ b/docs/releases/6.1.txt @@ -501,6 +501,13 @@ Models primary key when a ``QuerySet``'s ordering has been forcibly cleared by calling :meth:`~.QuerySet.order_by` with no arguments. +* As default model ordering is now applied to combined querysets, + :meth:`~.QuerySet.union`, :meth:`~.QuerySet.difference`, and + :meth:`~.QuerySet.intersection` raise ``DatabaseError`` when a field in + :attr:`.Options.ordering` isn't selected by :meth:`~.QuerySet.values` or + :meth:`~.QuerySet.values_list`. Call :meth:`~.QuerySet.order_by` without + arguments before combining to clear the default ordering. + * SQL ``SELECT`` aliases originating from :meth:`.QuerySet.annotate` calls as well as table and ``JOIN`` aliases are now systematically quoted to prevent special character collisions. Because quoted aliases are diff --git a/tests/queries/test_qs_combinators.py b/tests/queries/test_qs_combinators.py index a400ce76de41..944b360ee63e 100644 --- a/tests/queries/test_qs_combinators.py +++ b/tests/queries/test_qs_combinators.py @@ -21,6 +21,7 @@ Article, Author, Celebrity, + Cover, ExtraInfo, Note, Number, @@ -756,6 +757,16 @@ def test_order_raises_on_non_selected_column(self): # switched order, now 'exists' again: list(qs2.union(qs1).order_by("num")) + def test_order_by_non_selected_column_from_default_ordering(self): + qs = Cover.objects.values("title") + msg = "ORDER BY term does not match any column in the result set" + with self.assertRaisesMessage(DatabaseError, msg): + list(qs.union(qs)) + with self.assertRaisesMessage(DatabaseError, msg): + list(qs.intersection(qs)) + with self.assertRaisesMessage(DatabaseError, msg): + list(qs.difference(qs)) + @skipUnlessDBFeature("supports_select_difference", "supports_select_intersection") def test_qs_with_subcompound_qs(self): qs1 = Number.objects.all()