Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

magic-removal: Fixed #1219 - Added bulk delete for objects.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2029 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 00f93bc7bb47b626691a096e4bbc908c597a31ca 1 parent d9780b7
@freakboy3742 freakboy3742 authored
View
34 django/db/models/manager.py
@@ -48,7 +48,7 @@ def contribute_to_class(self, klass, name):
self.creation_counter < klass._default_manager.creation_counter:
klass._default_manager = self
- def _get_sql_clause(self, *args, **kwargs):
+ def _get_sql_clause(self, allow_joins, *args, **kwargs):
def quote_only_if_word(word):
if ' ' in word:
return word
@@ -63,7 +63,7 @@ def quote_only_if_word(word):
joins = SortedDict()
where = kwargs.get('where') and kwargs['where'][:] or []
params = kwargs.get('params') and kwargs['params'][:] or []
-
+
# Convert all the args into SQL.
table_count = 0
for arg in args:
@@ -77,7 +77,6 @@ def quote_only_if_word(word):
where.extend(where2)
params.extend(params2)
-
# Convert the kwargs into SQL.
tables2, joins2, where2, params2 = parse_lookup(kwargs.items(), opts)
tables.extend(tables2)
@@ -99,10 +98,14 @@ def quote_only_if_word(word):
# Start composing the body of the SQL statement.
sql = [" FROM", backend.quote_name(opts.db_table)]
+ # Check if extra tables are allowed. If not, throw an error
+ if (tables or joins) and not allow_joins:
+ raise TypeError("Joins are not allowed in this type of query")
+
# Compose the join dictionary into SQL describing the joins.
if joins:
sql.append(" ".join(["%s %s AS %s ON %s" % (join_type, table, alias, condition)
- for (alias, (table, join_type, condition)) in joins.items()]))
+ for (alias, (table, join_type, condition)) in joins.items()]))
# Compose the tables clause into SQL.
if tables:
@@ -146,13 +149,28 @@ def quote_only_if_word(word):
return select, " ".join(sql), params
+ def delete(self, *args, **kwargs):
+ # disable non-supported fields
+ kwargs['select_related'] = False
+ kwargs['select'] = {}
+ kwargs['order_by'] = []
+ kwargs['offset'] = None
+ kwargs['limit'] = None
+
+ opts = self.klass._meta
+
+ # Perform the SQL delete
+ cursor = connection.cursor()
+ _, sql, params = self._get_sql_clause(False, *args, **kwargs)
+ cursor.execute("DELETE " + sql, params)
+
def get_iterator(self, *args, **kwargs):
# kwargs['select'] is a dictionary, and dictionaries' key order is
# undefined, so we convert it to a list of tuples internally.
kwargs['select'] = kwargs.get('select', {}).items()
cursor = connection.cursor()
- select, sql, params = self._get_sql_clause(*args, **kwargs)
+ select, sql, params = self._get_sql_clause(True, *args, **kwargs)
cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
fill_cache = kwargs.get('select_related')
index_end = len(self.klass._meta.fields)
@@ -177,7 +195,7 @@ def get_count(self, *args, **kwargs):
kwargs['offset'] = None
kwargs['limit'] = None
kwargs['select_related'] = False
- _, sql, params = self._get_sql_clause(*args, **kwargs)
+ _, sql, params = self._get_sql_clause(True, *args, **kwargs)
cursor = connection.cursor()
cursor.execute("SELECT COUNT(*)" + sql, params)
return cursor.fetchone()[0]
@@ -209,7 +227,7 @@ def get_values_iterator(self, *args, **kwargs):
fields = [f.column for f in self.klass._meta.fields]
cursor = connection.cursor()
- _, sql, params = self._get_sql_clause(*args, **kwargs)
+ _, sql, params = self._get_sql_clause(True, *args, **kwargs)
select = ['%s.%s' % (backend.quote_name(self.klass._meta.db_table), backend.quote_name(f)) for f in fields]
cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
while 1:
@@ -239,7 +257,7 @@ def __get_date_list(self, field, kind, *args, **kwargs):
if field.null:
kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \
(backend.quote_name(self.klass._meta.db_table), backend.quote_name(field.column)))
- select, sql, params = self._get_sql_clause(*args, **kwargs)
+ select, sql, params = self._get_sql_clause(True, *args, **kwargs)
sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
(backend.get_date_trunc_sql(kind, '%s.%s' % (backend.quote_name(self.klass._meta.db_table),
backend.quote_name(field.column))), sql, order)
View
7 tests/modeltests/basic/models.py
@@ -203,6 +203,13 @@ class Article(models.Model):
...
AttributeError: Manager isn't accessible via Article instances
+# Bulk delete test: How many objects before and after the delete?
+>>> Article.objects.get_count()
+8L
+>>> Article.objects.delete(id__lte=4)
+>>> Article.objects.get_count()
+4L
+
"""
from django.conf import settings
View
7 tests/modeltests/many_to_one/models.py
@@ -83,7 +83,7 @@ def __repr__(self):
[This is a test, John's second story]
# The underlying query only makes one join when a related table is referenced twice.
->>> null, sql, null = Article.objects._get_sql_clause(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
+>>> null, sql, null = Article.objects._get_sql_clause(True, reporter__first_name__exact='John', reporter__last_name__exact='Smith')
>>> sql.count('INNER JOIN')
1
@@ -152,4 +152,9 @@ def __repr__(self):
>>> Reporter.objects.get_list(articles__reporter__first_name__startswith='John', distinct=True)
[John Smith]
+# Delete requiring join is prohibited
+>>> Article.objects.delete(reporter__first_name__startswith='Jo')
+Traceback (most recent call last):
+ ...
+TypeError: Joins are not allowed in this type of query
"""
Please sign in to comment.
Something went wrong with that request. Please try again.