1 """ |
1 """ |
2 Query subclasses which provide extra functionality beyond simple data retrieval. |
2 Query subclasses which provide extra functionality beyond simple data retrieval. |
3 """ |
3 """ |
4 |
4 |
5 from django.contrib.contenttypes import generic |
|
6 from django.core.exceptions import FieldError |
5 from django.core.exceptions import FieldError |
7 from django.db.models.sql.constants import * |
6 from django.db.models.sql.constants import * |
8 from django.db.models.sql.datastructures import RawValue, Date |
7 from django.db.models.sql.datastructures import Date |
9 from django.db.models.sql.query import Query |
8 from django.db.models.sql.query import Query |
10 from django.db.models.sql.where import AND |
9 from django.db.models.sql.where import AND |
11 |
10 |
12 __all__ = ['DeleteQuery', 'UpdateQuery', 'InsertQuery', 'DateQuery', |
11 __all__ = ['DeleteQuery', 'UpdateQuery', 'InsertQuery', 'DateQuery', |
13 'CountQuery'] |
12 'CountQuery'] |
41 the delete_batch() method. |
40 the delete_batch() method. |
42 |
41 |
43 More than one physical query may be executed if there are a |
42 More than one physical query may be executed if there are a |
44 lot of values in pk_list. |
43 lot of values in pk_list. |
45 """ |
44 """ |
|
45 from django.contrib.contenttypes import generic |
46 cls = self.model |
46 cls = self.model |
47 for related in cls._meta.get_all_related_many_to_many_objects(): |
47 for related in cls._meta.get_all_related_many_to_many_objects(): |
48 if not isinstance(related.field, generic.GenericRelation): |
48 if not isinstance(related.field, generic.GenericRelation): |
49 for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): |
49 for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): |
50 where = self.where_class() |
50 where = self.where_class() |
104 if not hasattr(self, 'related_updates'): |
104 if not hasattr(self, 'related_updates'): |
105 self.related_updates = {} |
105 self.related_updates = {} |
106 |
106 |
107 def clone(self, klass=None, **kwargs): |
107 def clone(self, klass=None, **kwargs): |
108 return super(UpdateQuery, self).clone(klass, |
108 return super(UpdateQuery, self).clone(klass, |
109 related_updates=self.related_updates.copy, **kwargs) |
109 related_updates=self.related_updates.copy(), **kwargs) |
110 |
110 |
111 def execute_sql(self, result_type=None): |
111 def execute_sql(self, result_type=None): |
112 super(UpdateQuery, self).execute_sql(result_type) |
112 """ |
|
113 Execute the specified update. Returns the number of rows affected by |
|
114 the primary update query (there could be other updates on related |
|
115 tables, but their rowcounts are not returned). |
|
116 """ |
|
117 cursor = super(UpdateQuery, self).execute_sql(result_type) |
|
118 rows = cursor.rowcount |
|
119 del cursor |
113 for query in self.get_related_updates(): |
120 for query in self.get_related_updates(): |
114 query.execute_sql(result_type) |
121 query.execute_sql(result_type) |
|
122 return rows |
115 |
123 |
116 def as_sql(self): |
124 def as_sql(self): |
117 """ |
125 """ |
118 Creates the SQL for this query. Returns the SQL string and list of |
126 Creates the SQL for this query. Returns the SQL string and list of |
119 parameters. |
127 parameters. |
283 self.params = () |
291 self.params = () |
284 |
292 |
285 def clone(self, klass=None, **kwargs): |
293 def clone(self, klass=None, **kwargs): |
286 extras = {'columns': self.columns[:], 'values': self.values[:], |
294 extras = {'columns': self.columns[:], 'values': self.values[:], |
287 'params': self.params} |
295 'params': self.params} |
288 return super(InsertQuery, self).clone(klass, extras) |
296 extras.update(kwargs) |
|
297 return super(InsertQuery, self).clone(klass, **extras) |
289 |
298 |
290 def as_sql(self): |
299 def as_sql(self): |
291 # We don't need quote_name_unless_alias() here, since these are all |
300 # We don't need quote_name_unless_alias() here, since these are all |
292 # going to be column names (so we can avoid the extra overhead). |
301 # going to be column names (so we can avoid the extra overhead). |
293 qn = self.connection.ops.quote_name |
302 qn = self.connection.ops.quote_name |
333 """ |
342 """ |
334 A DateQuery is a normal query, except that it specifically selects a single |
343 A DateQuery is a normal query, except that it specifically selects a single |
335 date field. This requires some special handling when converting the results |
344 date field. This requires some special handling when converting the results |
336 back to Python objects, so we put it in a separate class. |
345 back to Python objects, so we put it in a separate class. |
337 """ |
346 """ |
|
347 def __getstate__(self): |
|
348 """ |
|
349 Special DateQuery-specific pickle handling. |
|
350 """ |
|
351 for elt in self.select: |
|
352 if isinstance(elt, Date): |
|
353 # Eliminate a method reference that can't be pickled. The |
|
354 # __setstate__ method restores this. |
|
355 elt.date_sql_func = None |
|
356 return super(DateQuery, self).__getstate__() |
|
357 |
|
358 def __setstate__(self, obj_dict): |
|
359 super(DateQuery, self).__setstate__(obj_dict) |
|
360 for elt in self.select: |
|
361 if isinstance(elt, Date): |
|
362 self.date_sql_func = self.connection.ops.date_trunc_sql |
|
363 |
338 def results_iter(self): |
364 def results_iter(self): |
339 """ |
365 """ |
340 Returns an iterator over the results from executing this query. |
366 Returns an iterator over the results from executing this query. |
341 """ |
367 """ |
342 resolve_columns = hasattr(self, 'resolve_columns') |
368 resolve_columns = hasattr(self, 'resolve_columns') |
350 offset = len(self.extra_select) |
376 offset = len(self.extra_select) |
351 for rows in self.execute_sql(MULTI): |
377 for rows in self.execute_sql(MULTI): |
352 for row in rows: |
378 for row in rows: |
353 date = row[offset] |
379 date = row[offset] |
354 if resolve_columns: |
380 if resolve_columns: |
355 date = self.resolve_columns([date], fields)[0] |
381 date = self.resolve_columns(row, fields)[offset] |
356 elif needs_string_cast: |
382 elif needs_string_cast: |
357 date = typecast_timestamp(str(date)) |
383 date = typecast_timestamp(str(date)) |
358 yield date |
384 yield date |
359 |
385 |
360 def add_date_select(self, column, lookup_type, order='ASC'): |
386 def add_date_select(self, field, lookup_type, order='ASC'): |
361 """ |
387 """ |
362 Converts the query into a date extraction query. |
388 Converts the query into a date extraction query. |
363 """ |
389 """ |
364 alias = self.join((None, self.model._meta.db_table, None, None)) |
390 result = self.setup_joins([field.name], self.get_meta(), |
365 select = Date((alias, column), lookup_type, |
391 self.get_initial_alias(), False) |
|
392 alias = result[3][-1] |
|
393 select = Date((alias, field.column), lookup_type, |
366 self.connection.ops.date_trunc_sql) |
394 self.connection.ops.date_trunc_sql) |
367 self.select = [select] |
395 self.select = [select] |
368 self.select_fields = [None] |
396 self.select_fields = [None] |
369 self.select_related = False # See #7097. |
397 self.select_related = False # See #7097. |
|
398 self.extra_select = {} |
370 self.distinct = True |
399 self.distinct = True |
371 self.order_by = order == 'ASC' and [1] or [-1] |
400 self.order_by = order == 'ASC' and [1] or [-1] |
372 |
401 |
373 class CountQuery(Query): |
402 class CountQuery(Query): |
374 """ |
403 """ |