Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Russell Keith-Magee authored January 17, 2006
34  django/db/models/manager.py
@@ -48,7 +48,7 @@ def contribute_to_class(self, klass, name):
48 48
            self.creation_counter < klass._default_manager.creation_counter:
49 49
                 klass._default_manager = self
50 50
 
51  
-    def _get_sql_clause(self, *args, **kwargs):
  51
+    def _get_sql_clause(self, allow_joins, *args, **kwargs):
52 52
         def quote_only_if_word(word):
53 53
             if ' ' in word:
54 54
                 return word
@@ -63,7 +63,7 @@ def quote_only_if_word(word):
63 63
         joins = SortedDict()
64 64
         where = kwargs.get('where') and kwargs['where'][:] or []
65 65
         params = kwargs.get('params') and kwargs['params'][:] or []
66  
-
  66
+        
67 67
         # Convert all the args into SQL.
68 68
         table_count = 0
69 69
         for arg in args:
@@ -77,7 +77,6 @@ def quote_only_if_word(word):
77 77
             where.extend(where2)
78 78
             params.extend(params2)
79 79
 
80  
-
81 80
         # Convert the kwargs into SQL.
82 81
         tables2, joins2, where2, params2 = parse_lookup(kwargs.items(), opts)
83 82
         tables.extend(tables2)
@@ -99,10 +98,14 @@ def quote_only_if_word(word):
99 98
         # Start composing the body of the SQL statement.
100 99
         sql = [" FROM", backend.quote_name(opts.db_table)]
101 100
 
  101
+        # Check if extra tables are allowed. If not, throw an error
  102
+        if (tables or joins) and not allow_joins:
  103
+            raise TypeError("Joins are not allowed in this type of query")
  104
+
102 105
         # Compose the join dictionary into SQL describing the joins.
103 106
         if joins:
104 107
             sql.append(" ".join(["%s %s AS %s ON %s" % (join_type, table, alias, condition)
105  
-                                for (alias, (table, join_type, condition)) in joins.items()]))
  108
+                            for (alias, (table, join_type, condition)) in joins.items()]))
106 109
 
107 110
         # Compose the tables clause into SQL.
108 111
         if tables:
@@ -146,13 +149,28 @@ def quote_only_if_word(word):
146 149
 
147 150
         return select, " ".join(sql), params
148 151
 
  152
+    def delete(self, *args, **kwargs):
  153
+        # disable non-supported fields
  154
+        kwargs['select_related'] = False
  155
+        kwargs['select'] = {}
  156
+        kwargs['order_by'] = []
  157
+        kwargs['offset'] = None
  158
+        kwargs['limit'] = None
  159
+        
  160
+        opts = self.klass._meta
  161
+
  162
+        # Perform the SQL delete
  163
+        cursor = connection.cursor()
  164
+        _, sql, params = self._get_sql_clause(False, *args, **kwargs)
  165
+        cursor.execute("DELETE " + sql, params)
  166
+        
149 167
     def get_iterator(self, *args, **kwargs):
150 168
         # kwargs['select'] is a dictionary, and dictionaries' key order is
151 169
         # undefined, so we convert it to a list of tuples internally.
152 170
         kwargs['select'] = kwargs.get('select', {}).items()
153 171
 
154 172
         cursor = connection.cursor()
155  
-        select, sql, params = self._get_sql_clause(*args, **kwargs)
  173
+        select, sql, params = self._get_sql_clause(True, *args, **kwargs)
156 174
         cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
157 175
         fill_cache = kwargs.get('select_related')
158 176
         index_end = len(self.klass._meta.fields)
@@ -177,7 +195,7 @@ def get_count(self, *args, **kwargs):
177 195
         kwargs['offset'] = None
178 196
         kwargs['limit'] = None
179 197
         kwargs['select_related'] = False
180  
-        _, sql, params = self._get_sql_clause(*args, **kwargs)
  198
+        _, sql, params = self._get_sql_clause(True, *args, **kwargs)
181 199
         cursor = connection.cursor()
182 200
         cursor.execute("SELECT COUNT(*)" + sql, params)
183 201
         return cursor.fetchone()[0]
@@ -209,7 +227,7 @@ def get_values_iterator(self, *args, **kwargs):
209 227
             fields = [f.column for f in self.klass._meta.fields]
210 228
 
211 229
         cursor = connection.cursor()
212  
-        _, sql, params = self._get_sql_clause(*args, **kwargs)
  230
+        _, sql, params = self._get_sql_clause(True, *args, **kwargs)
213 231
         select = ['%s.%s' % (backend.quote_name(self.klass._meta.db_table), backend.quote_name(f)) for f in fields]
214 232
         cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
215 233
         while 1:
@@ -239,7 +257,7 @@ def __get_date_list(self, field, kind, *args, **kwargs):
239 257
         if field.null:
240 258
             kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \
241 259
                 (backend.quote_name(self.klass._meta.db_table), backend.quote_name(field.column)))
242  
-        select, sql, params = self._get_sql_clause(*args, **kwargs)
  260
+        select, sql, params = self._get_sql_clause(True, *args, **kwargs)
243 261
         sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
244 262
             (backend.get_date_trunc_sql(kind, '%s.%s' % (backend.quote_name(self.klass._meta.db_table),
245 263
             backend.quote_name(field.column))), sql, order)
7  tests/modeltests/basic/models.py
@@ -203,6 +203,13 @@ class Article(models.Model):
203 203
     ...
204 204
 AttributeError: Manager isn't accessible via Article instances
205 205
 
  206
+# Bulk delete test: How many objects before and after the delete?
  207
+>>> Article.objects.get_count()
  208
+8L
  209
+>>> Article.objects.delete(id__lte=4)
  210
+>>> Article.objects.get_count()
  211
+4L
  212
+
206 213
 """
207 214
 
208 215
 from django.conf import settings
7  tests/modeltests/many_to_one/models.py
@@ -83,7 +83,7 @@ def __repr__(self):
83 83
 [This is a test, John's second story]
84 84
 
85 85
 # The underlying query only makes one join when a related table is referenced twice.
86  
->>> null, sql, null = Article.objects._get_sql_clause(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
  86
+>>> null, sql, null = Article.objects._get_sql_clause(True, reporter__first_name__exact='John', reporter__last_name__exact='Smith')
87 87
 >>> sql.count('INNER JOIN')
88 88
 1
89 89
 
@@ -152,4 +152,9 @@ def __repr__(self):
152 152
 >>> Reporter.objects.get_list(articles__reporter__first_name__startswith='John', distinct=True)
153 153
 [John Smith]
154 154
 
  155
+# Delete requiring join is prohibited
  156
+>>> Article.objects.delete(reporter__first_name__startswith='Jo')
  157
+Traceback (most recent call last):
  158
+    ...
  159
+TypeError: Joins are not allowed in this type of query
155 160
 """

0 notes on commit 00f93bc

Please sign in to comment.
Something went wrong with that request. Please try again.