app/django/db/models/sql/subqueries.py
changeset 323 ff1a9aa48cfd
parent 54 03e267d67478
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
     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     """
   380         result, params = self._query.as_sql()
   409         result, params = self._query.as_sql()
   381         return ['(%s) A1' % result], params
   410         return ['(%s) A1' % result], params
   382 
   411 
   383     def get_ordering(self):
   412     def get_ordering(self):
   384         return ()
   413         return ()
   385