From 28e2077148f7602d29165e90965974698819cbba Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Tue, 4 Jul 2023 17:34:20 -0400 Subject: [PATCH] Refs #32433 -- Reallowed calling QuerySet.delete() after distinct(). While values(*field_excluding_pk).distinct() and distinct(*field_excluding_pk) can reduce the number of resulting rows in a way that makes subsequent delete() calls ambiguous standalone .distinct() calls cannot. Since delete() already disallows chain usages with values() the only case that needs to be handled, as originally reported, is when DISTINCT ON is used via distinct(*fields). Refs #32682 which had to resort to subqueries to prevent duplicates in the admin and caused significant performance regressions on MySQL (refs #34639). This partly reverts 6307c3f1a123f5975c73b231e8ac4f115fd72c0d. --- django/db/models/query.py | 4 ++-- tests/delete_regress/tests.py | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/django/db/models/query.py b/django/db/models/query.py index a5b0f464a9..5ac2407ea3 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -1135,8 +1135,8 @@ class QuerySet(AltersData): self._not_support_combined_queries("delete") if self.query.is_sliced: raise TypeError("Cannot use 'limit' or 'offset' with delete().") - if self.query.distinct or self.query.distinct_fields: - raise TypeError("Cannot call delete() after .distinct().") + if self.query.distinct_fields: + raise TypeError("Cannot call delete() after .distinct(*fields).") if self._fields is not None: raise TypeError("Cannot call delete() after .values() or .values_list()") diff --git a/tests/delete_regress/tests.py b/tests/delete_regress/tests.py index 2540fd2802..71e3bcb405 100644 --- a/tests/delete_regress/tests.py +++ b/tests/delete_regress/tests.py @@ -396,10 +396,8 @@ class DeleteTests(TestCase): class DeleteDistinct(SimpleTestCase): - def test_disallowed_delete_distinct(self): - msg = "Cannot call delete() after .distinct()." - with self.assertRaisesMessage(TypeError, msg): - Book.objects.distinct().delete() + def test_disallowed_delete_distinct_on(self): + msg = "Cannot call delete() after .distinct(*fields)." with self.assertRaisesMessage(TypeError, msg): Book.objects.distinct("id").delete()