2 Query subclasses which provide extra functionality beyond simple data retrieval.
5 from django
.core
.exceptions
import FieldError
6 from django
.db
import connections
7 from django
.db
.models
.sql
.constants
import *
8 from django
.db
.models
.sql
.datastructures
import Date
9 from django
.db
.models
.sql
.expressions
import SQLEvaluator
10 from django
.db
.models
.sql
.query
import Query
11 from django
.db
.models
.sql
.where
import AND
, Constraint
13 __all__
= ['DeleteQuery', 'UpdateQuery', 'InsertQuery', 'DateQuery',
16 class DeleteQuery(Query
):
18 Delete queries are done through this class, since they are more constrained
22 compiler
= 'SQLDeleteCompiler'
24 def do_query(self
, table
, where
, using
):
27 self
.get_compiler(using
).execute_sql(None)
29 def delete_batch(self
, pk_list
, using
):
31 Set up and execute delete queries for all the objects in pk_list.
33 More than one physical query may be executed if there are a
34 lot of values in pk_list.
36 for offset
in range(0, len(pk_list
), GET_ITERATOR_CHUNK_SIZE
):
37 where
= self
.where_class()
38 field
= self
.model
._meta
.pk
39 where
.add((Constraint(None, field
.column
, field
), 'in',
40 pk_list
[offset
: offset
+ GET_ITERATOR_CHUNK_SIZE
]), AND
)
41 self
.do_query(self
.model
._meta
.db_table
, where
, using
=using
)
43 class UpdateQuery(Query
):
45 Represents an "update" SQL query.
48 compiler
= 'SQLUpdateCompiler'
50 def __init__(self
, *args
, **kwargs
):
51 super(UpdateQuery
, self
).__init
__(*args
, **kwargs
)
54 def _setup_query(self
):
56 Runs on initialization and after cloning. Any attributes that would
57 normally be set in __init__ should go in here, instead, so that they
58 are also set up after a clone() call.
61 self
.related_ids
= None
62 if not hasattr(self
, 'related_updates'):
63 self
.related_updates
= {}
65 def clone(self
, klass
=None, **kwargs
):
66 return super(UpdateQuery
, self
).clone(klass
,
67 related_updates
=self
.related_updates
.copy(), **kwargs
)
70 def clear_related(self
, related_field
, pk_list
, using
):
72 Set up and execute an update query that clears related entries for the
75 This is used by the QuerySet.delete_objects() method.
77 for offset
in range(0, len(pk_list
), GET_ITERATOR_CHUNK_SIZE
):
78 self
.where
= self
.where_class()
79 f
= self
.model
._meta
.pk
80 self
.where
.add((Constraint(None, f
.column
, f
), 'in',
81 pk_list
[offset
: offset
+ GET_ITERATOR_CHUNK_SIZE
]),
83 self
.values
= [(related_field
, None, None)]
84 self
.get_compiler(using
).execute_sql(None)
86 def add_update_values(self
, values
):
88 Convert a dictionary of field name to value mappings into an update
89 query. This is the entry point for the public update() method on
93 for name
, val
in values
.iteritems():
94 field
, model
, direct
, m2m
= self
.model
._meta
.get_field_by_name(name
)
96 raise FieldError('Cannot update model field %r (only non-relations and foreign keys permitted).' % field
)
98 self
.add_related_update(model
, field
, val
)
100 values_seq
.append((field
, model
, val
))
101 return self
.add_update_fields(values_seq
)
103 def add_update_fields(self
, values_seq
):
105 Turn a sequence of (field, model, value) triples into an update query.
106 Used by add_update_values() as well as the "fast" update path when
109 self
.values
.extend(values_seq
)
111 def add_related_update(self
, model
, field
, value
):
113 Adds (name, value) to an update query for an ancestor model.
115 Updates are coalesced so that we only run one update query per ancestor.
118 self
.related_updates
[model
].append((field
, None, value
))
120 self
.related_updates
[model
] = [(field
, None, value
)]
122 def get_related_updates(self
):
124 Returns a list of query objects: one for each update required to an
125 ancestor model. Each query will have the same filtering conditions as
126 the current query but will only update a single table.
128 if not self
.related_updates
:
131 for model
, values
in self
.related_updates
.iteritems():
132 query
= UpdateQuery(model
)
133 query
.values
= values
134 if self
.related_ids
is not None:
135 query
.add_filter(('pk__in', self
.related_ids
))
139 class InsertQuery(Query
):
140 compiler
= 'SQLInsertCompiler'
142 def __init__(self
, *args
, **kwargs
):
143 super(InsertQuery
, self
).__init
__(*args
, **kwargs
)
148 def clone(self
, klass
=None, **kwargs
):
150 'columns': self
.columns
[:],
151 'values': self
.values
[:],
152 'params': self
.params
154 extras
.update(kwargs
)
155 return super(InsertQuery
, self
).clone(klass
, **extras
)
157 def insert_values(self
, insert_values
, raw_values
=False):
159 Set up the insert query from the 'insert_values' dictionary. The
160 dictionary gives the model field names and their target values.
162 If 'raw_values' is True, the values in the 'insert_values' dictionary
163 are inserted directly into the query, rather than passed as SQL
164 parameters. This provides a way to insert NULL and DEFAULT keywords
165 into the query, for example.
167 placeholders
, values
= [], []
168 for field
, val
in insert_values
:
169 placeholders
.append((field
, val
))
170 self
.columns
.append(field
.column
)
173 self
.values
.extend([(None, v
) for v
in values
])
175 self
.params
+= tuple(values
)
176 self
.values
.extend(placeholders
)
178 class DateQuery(Query
):
180 A DateQuery is a normal query, except that it specifically selects a single
181 date field. This requires some special handling when converting the results
182 back to Python objects, so we put it in a separate class.
185 compiler
= 'SQLDateCompiler'
187 def add_date_select(self
, field
, lookup_type
, order
='ASC'):
189 Converts the query into a date extraction query.
191 result
= self
.setup_joins([field
.name
], self
.get_meta(),
192 self
.get_initial_alias(), False)
193 alias
= result
[3][-1]
194 select
= Date((alias
, field
.column
), lookup_type
)
195 self
.select
= [select
]
196 self
.select_fields
= [None]
197 self
.select_related
= False # See #7097.
198 self
.set_extra_mask([])
200 self
.order_by
= order
== 'ASC' and [1] or [-1]
202 class AggregateQuery(Query
):
204 An AggregateQuery takes another query as a parameter to the FROM
205 clause and only selects the elements in the provided list.
208 compiler
= 'SQLAggregateCompiler'
210 def add_subquery(self
, query
, using
):
211 self
.subquery
, self
.sub_params
= query
.get_compiler(using
).as_sql(with_col_aliases
=True)