From 1cd6e04cd4f768bcd4385b75de433d497d938f82 Mon Sep 17 00:00:00 2001 From: Anssi Kääriäinen Date: Thu, 20 Sep 2012 18:51:30 +0300 Subject: Fixed #18676 -- Allow fast-path deletion of objects Objects can be fast-path deleted if there are no signals, and there are no further cascades. If fast-path is taken, the objects do not need to be loaded into memory before deletion. Thanks to Jeremy Dunck, Simon Charette and Alex Gaynor for reviewing the patch. --- django/db/models/sql/compiler.py | 3 ++- django/db/models/sql/subqueries.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'django/db/models/sql') diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index f06d6b11a4..f6b6bba1d9 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -934,7 +934,8 @@ class SQLDeleteCompiler(SQLCompiler): qn = self.quote_name_unless_alias result = ['DELETE FROM %s' % qn(self.query.tables[0])] where, params = self.query.where.as_sql(qn=qn, connection=self.connection) - result.append('WHERE %s' % where) + if where: + result.append('WHERE %s' % where) return ' '.join(result), tuple(params) class SQLUpdateCompiler(SQLCompiler): diff --git a/django/db/models/sql/subqueries.py b/django/db/models/sql/subqueries.py index c6995c6abb..9f3fb8ac22 100644 --- a/django/db/models/sql/subqueries.py +++ b/django/db/models/sql/subqueries.py @@ -3,6 +3,7 @@ Query subclasses which provide extra functionality beyond simple data retrieval. """ from django.core.exceptions import FieldError +from django.db import connections from django.db.models.constants import LOOKUP_SEP from django.db.models.fields import DateField, FieldDoesNotExist from django.db.models.sql.constants import * @@ -46,6 +47,37 @@ class DeleteQuery(Query): pk_list[offset:offset + GET_ITERATOR_CHUNK_SIZE]), AND) self.do_query(self.model._meta.db_table, where, using=using) + def delete_qs(self, query, using): + innerq = query.query + # Make sure the inner query has at least one table in use. + innerq.get_initial_alias() + # The same for our new query. + self.get_initial_alias() + innerq_used_tables = [t for t in innerq.tables + if innerq.alias_refcount[t]] + if ((not innerq_used_tables or innerq_used_tables == self.tables) + and not len(innerq.having)): + # There is only the base table in use in the query, and there are + # no aggregate filtering going on. + self.where = innerq.where + else: + pk = query.model._meta.pk + if not connections[using].features.update_can_self_select: + # We can't do the delete using subquery. + values = list(query.values_list('pk', flat=True)) + if not values: + return + self.delete_batch(values, using) + return + else: + values = innerq + innerq.select = [(self.get_initial_alias(), pk.column)] + where = self.where_class() + where.add((Constraint(None, pk.column, pk), 'in', values), AND) + self.where = where + self.get_compiler(using).execute_sql(None) + + class UpdateQuery(Query): """ Represents an "update" SQL query. -- cgit v1.3