1
0
mirror of https://github.com/django/django.git synced 2025-06-05 11:39:13 +00:00

Fixed #33759 -- Avoided unnecessary subquery in QuerySet.delete() with self-referential subqueries if supported.

This commit is contained in:
4the4ryushin 2023-04-28 02:33:25 +05:30 committed by Mariusz Felisiak
parent 5a6d4d3bfd
commit 0b0998dc15
4 changed files with 21 additions and 9 deletions

View File

@ -12,6 +12,9 @@ class BaseDatabaseFeatures:
allows_group_by_select_index = True allows_group_by_select_index = True
empty_fetchmany_value = [] empty_fetchmany_value = []
update_can_self_select = True update_can_self_select = True
# Does the backend support self-reference subqueries in the DELETE
# statement?
delete_can_self_reference_subquery = True
# Does the backend distinguish between '' and None? # Does the backend distinguish between '' and None?
interprets_empty_strings_as_nulls = False interprets_empty_strings_as_nulls = False

View File

@ -24,6 +24,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_slicing_ordering_in_compound = True supports_slicing_ordering_in_compound = True
supports_index_on_text_field = False supports_index_on_text_field = False
supports_update_conflicts = True supports_update_conflicts = True
delete_can_self_reference_subquery = False
create_test_procedure_without_params_sql = """ create_test_procedure_without_params_sql = """
CREATE PROCEDURE test_procedure () CREATE PROCEDURE test_procedure ()
BEGIN BEGIN

View File

@ -1890,7 +1890,10 @@ class SQLDeleteCompiler(SQLCompiler):
Create the SQL for this query. Return the SQL string and list of Create the SQL for this query. Return the SQL string and list of
parameters. parameters.
""" """
if self.single_alias and not self.contains_self_reference_subquery: if self.single_alias and (
self.connection.features.delete_can_self_reference_subquery
or not self.contains_self_reference_subquery
):
return self._as_sql(self.query) return self._as_sql(self.query)
innerq = self.query.clone() innerq = self.query.clone()
innerq.__class__ = Query innerq.__class__ = Query

View File

@ -379,15 +379,20 @@ class DeleteTests(TestCase):
child = Child.objects.create(name="Juan") child = Child.objects.create(name="Juan")
Book.objects.create(pagecount=500, owner=child) Book.objects.create(pagecount=500, owner=child)
PlayedWith.objects.create(child=child, toy=toy, date=datetime.date.today()) PlayedWith.objects.create(child=child, toy=toy, date=datetime.date.today())
Book.objects.filter( with self.assertNumQueries(1) as ctx:
Exists( Book.objects.filter(
Book.objects.filter( Exists(
pk=OuterRef("pk"), Book.objects.filter(
owner__toys=toy.pk, pk=OuterRef("pk"),
), owner__toys=toy.pk,
) ),
).delete() )
).delete()
self.assertIs(Book.objects.exists(), False) self.assertIs(Book.objects.exists(), False)
sql = ctx.captured_queries[0]["sql"].lower()
if connection.features.delete_can_self_reference_subquery:
self.assertEqual(sql.count("select"), 1)
class DeleteDistinct(SimpleTestCase): class DeleteDistinct(SimpleTestCase):