summaryrefslogtreecommitdiff
path: root/django/db/models/sql
diff options
context:
space:
mode:
authorAnssi Kääriäinen <akaariai@gmail.com>2012-09-20 18:51:30 +0300
committerAnssi Kääriäinen <akaariai@gmail.com>2012-09-28 18:16:08 +0300
commit1cd6e04cd4f768bcd4385b75de433d497d938f82 (patch)
tree9aa9611692cd492cc6666c3c3a02df2fd2c7df91 /django/db/models/sql
parent3fcca0e94721a734882389ce473f522d293907e9 (diff)
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.
Diffstat (limited to 'django/db/models/sql')
-rw-r--r--django/db/models/sql/compiler.py3
-rw-r--r--django/db/models/sql/subqueries.py32
2 files changed, 34 insertions, 1 deletions
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.