summaryrefslogtreecommitdiff
path: root/django/db/models/sql
diff options
context:
space:
mode:
authorBrian Rosner <brosner@gmail.com>2008-04-28 14:43:46 +0000
committerBrian Rosner <brosner@gmail.com>2008-04-28 14:43:46 +0000
commit886005078d66bd779ad3d6434d5699fbc17cfed1 (patch)
treea8b94b81b22e84b8223c37de2c00710a3b221f02 /django/db/models/sql
parent738e6d986ba41ec5ef9ba5a600a333916f2e763d (diff)
newforms-admin: Merged from trunk up to [7499].
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7500 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db/models/sql')
-rw-r--r--django/db/models/sql/query.py35
-rw-r--r--django/db/models/sql/subqueries.py23
2 files changed, 49 insertions, 9 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 59b2ebdd68..7e9fb00418 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -99,6 +99,24 @@ class Query(object):
memo[id(self)] = result
return result
+ def __getstate__(self):
+ """
+ Pickling support.
+ """
+ obj_dict = self.__dict__.copy()
+ del obj_dict['connection']
+ return obj_dict
+
+ def __setstate__(self, obj_dict):
+ """
+ Unpickling support.
+ """
+ self.__dict__.update(obj_dict)
+ # XXX: Need a better solution for this when multi-db stuff is
+ # supported. It's the only class-reference to the module-level
+ # connection variable.
+ self.connection = connection
+
def get_meta(self):
"""
Returns the Options instance (the model._meta) from which to start
@@ -895,9 +913,15 @@ class Query(object):
Add a single filter to the query. The 'filter_expr' is a pair:
(filter_string, value). E.g. ('name__contains', 'fred')
- If 'negate' is True, this is an exclude() filter. If 'trim' is True, we
- automatically trim the final join group (used internally when
- constructing nested queries).
+ If 'negate' is True, this is an exclude() filter. It's important to
+ note that this method does not negate anything in the where-clause
+ object when inserting the filter constraints. This is because negated
+ filters often require multiple calls to add_filter() and the negation
+ should only happen once. So the caller is responsible for this (the
+ caller will normally be add_q(), so that as an example).
+
+ If 'trim' is True, we automatically trim the final join group (used
+ internally when constructing nested queries).
If 'can_reuse' is a set, we are processing a component of a
multi-component filter (e.g. filter(Q1, Q2)). In this case, 'can_reuse'
@@ -1001,7 +1025,6 @@ class Query(object):
self.where.add((alias, col, field, lookup_type, value), connector)
if negate:
- self.where.negate()
for alias in join_list:
self.promote_alias(alias)
if final > 1 and lookup_type != 'isnull':
@@ -1039,12 +1062,12 @@ class Query(object):
self.where.start_subtree(connector)
self.add_q(child, used_aliases)
self.where.end_subtree()
- if q_object.negated:
- self.where.children[-1].negate()
else:
self.add_filter(child, connector, q_object.negated,
can_reuse=used_aliases)
connector = q_object.connector
+ if q_object.negated:
+ self.where.negate()
if subtree:
self.where.end_subtree()
diff --git a/django/db/models/sql/subqueries.py b/django/db/models/sql/subqueries.py
index 1f9a13ecdc..7385cd00e1 100644
--- a/django/db/models/sql/subqueries.py
+++ b/django/db/models/sql/subqueries.py
@@ -159,20 +159,37 @@ class UpdateQuery(Query):
# from other tables.
query = self.clone(klass=Query)
query.bump_prefix()
- query.select = []
query.extra_select = {}
- query.add_fields([query.model._meta.pk.name])
+ first_table = query.tables[0]
+ if query.alias_refcount[first_table] == 1:
+ # We can remove one table from the inner query.
+ query.unref_alias(first_table)
+ for i in xrange(1, len(query.tables)):
+ table = query.tables[i]
+ if query.alias_refcount[table]:
+ break
+ join_info = query.alias_map[table]
+ query.select = [(join_info[RHS_ALIAS], join_info[RHS_JOIN_COL])]
+ must_pre_select = False
+ else:
+ query.select = []
+ query.add_fields([query.model._meta.pk.name])
+ must_pre_select = not self.connection.features.update_can_self_select
# Now we adjust the current query: reset the where clause and get rid
# of all the tables we don't need (since they're in the sub-select).
self.where = self.where_class()
- if self.related_updates:
+ if self.related_updates or must_pre_select:
+ # Either we're using the idents in multiple update queries (so
+ # don't want them to change), or the db backend doesn't support
+ # selecting from the updating table (e.g. MySQL).
idents = []
for rows in query.execute_sql(MULTI):
idents.extend([r[0] for r in rows])
self.add_filter(('pk__in', idents))
self.related_ids = idents
else:
+ # The fast path. Filters and updates in one query.
self.add_filter(('pk__in', query))
for alias in self.tables[1:]:
self.alias_refcount[alias] = 0