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
This commit is contained in:
parent
d9780b7bd5
commit
00f93bc7bb
|
@ -48,7 +48,7 @@ class Manager(object):
|
||||||
self.creation_counter < klass._default_manager.creation_counter:
|
self.creation_counter < klass._default_manager.creation_counter:
|
||||||
klass._default_manager = self
|
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):
|
def quote_only_if_word(word):
|
||||||
if ' ' in word:
|
if ' ' in word:
|
||||||
return word
|
return word
|
||||||
|
@ -77,7 +77,6 @@ class Manager(object):
|
||||||
where.extend(where2)
|
where.extend(where2)
|
||||||
params.extend(params2)
|
params.extend(params2)
|
||||||
|
|
||||||
|
|
||||||
# Convert the kwargs into SQL.
|
# Convert the kwargs into SQL.
|
||||||
tables2, joins2, where2, params2 = parse_lookup(kwargs.items(), opts)
|
tables2, joins2, where2, params2 = parse_lookup(kwargs.items(), opts)
|
||||||
tables.extend(tables2)
|
tables.extend(tables2)
|
||||||
|
@ -99,10 +98,14 @@ class Manager(object):
|
||||||
# Start composing the body of the SQL statement.
|
# Start composing the body of the SQL statement.
|
||||||
sql = [" FROM", backend.quote_name(opts.db_table)]
|
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.
|
# Compose the join dictionary into SQL describing the joins.
|
||||||
if joins:
|
if joins:
|
||||||
sql.append(" ".join(["%s %s AS %s ON %s" % (join_type, table, alias, condition)
|
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.
|
# Compose the tables clause into SQL.
|
||||||
if tables:
|
if tables:
|
||||||
|
@ -146,13 +149,28 @@ class Manager(object):
|
||||||
|
|
||||||
return select, " ".join(sql), params
|
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):
|
def get_iterator(self, *args, **kwargs):
|
||||||
# kwargs['select'] is a dictionary, and dictionaries' key order is
|
# kwargs['select'] is a dictionary, and dictionaries' key order is
|
||||||
# undefined, so we convert it to a list of tuples internally.
|
# undefined, so we convert it to a list of tuples internally.
|
||||||
kwargs['select'] = kwargs.get('select', {}).items()
|
kwargs['select'] = kwargs.get('select', {}).items()
|
||||||
|
|
||||||
cursor = connection.cursor()
|
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)
|
cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
|
||||||
fill_cache = kwargs.get('select_related')
|
fill_cache = kwargs.get('select_related')
|
||||||
index_end = len(self.klass._meta.fields)
|
index_end = len(self.klass._meta.fields)
|
||||||
|
@ -177,7 +195,7 @@ class Manager(object):
|
||||||
kwargs['offset'] = None
|
kwargs['offset'] = None
|
||||||
kwargs['limit'] = None
|
kwargs['limit'] = None
|
||||||
kwargs['select_related'] = False
|
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 = connection.cursor()
|
||||||
cursor.execute("SELECT COUNT(*)" + sql, params)
|
cursor.execute("SELECT COUNT(*)" + sql, params)
|
||||||
return cursor.fetchone()[0]
|
return cursor.fetchone()[0]
|
||||||
|
@ -209,7 +227,7 @@ class Manager(object):
|
||||||
fields = [f.column for f in self.klass._meta.fields]
|
fields = [f.column for f in self.klass._meta.fields]
|
||||||
|
|
||||||
cursor = connection.cursor()
|
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]
|
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)
|
cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
|
||||||
while 1:
|
while 1:
|
||||||
|
@ -239,7 +257,7 @@ class Manager(object):
|
||||||
if field.null:
|
if field.null:
|
||||||
kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \
|
kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \
|
||||||
(backend.quote_name(self.klass._meta.db_table), backend.quote_name(field.column)))
|
(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' % \
|
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.get_date_trunc_sql(kind, '%s.%s' % (backend.quote_name(self.klass._meta.db_table),
|
||||||
backend.quote_name(field.column))), sql, order)
|
backend.quote_name(field.column))), sql, order)
|
||||||
|
|
|
@ -203,6 +203,13 @@ Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
AttributeError: Manager isn't accessible via Article instances
|
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
|
from django.conf import settings
|
||||||
|
|
|
@ -83,7 +83,7 @@ This is a test
|
||||||
[This is a test, John's second story]
|
[This is a test, John's second story]
|
||||||
|
|
||||||
# The underlying query only makes one join when a related table is referenced twice.
|
# 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')
|
>>> sql.count('INNER JOIN')
|
||||||
1
|
1
|
||||||
|
|
||||||
|
@ -152,4 +152,9 @@ John Smith
|
||||||
>>> Reporter.objects.get_list(articles__reporter__first_name__startswith='John', distinct=True)
|
>>> Reporter.objects.get_list(articles__reporter__first_name__startswith='John', distinct=True)
|
||||||
[John Smith]
|
[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
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue