summaryrefslogtreecommitdiff
path: root/django/db/models/sql
diff options
context:
space:
mode:
authorAnssi Kääriäinen <akaariai@gmail.com>2012-11-22 20:27:28 +0200
committerAnssi Kääriäinen <akaariai@gmail.com>2012-11-23 19:53:04 +0200
commit90b86291d022a09031d1df397d7aaebc30e435f7 (patch)
treed0264a1fee77724db1660d8ac807c4689189051d /django/db/models/sql
parent7b9a1fb9649d169f4ec0e539c4901c66b0f5ebb6 (diff)
Fixed #18375 -- Removed dict-ordering dependency for F-expressions
F() expressions reuse joins like any lookup in a .filter() call - reuse multijoins generated in the same .filter() call else generate new joins. Also, lookups can now reuse joins generated by F(). This change is backwards incompatible, but it is required to prevent dict randomization from generating different queries depending on .filter() kwarg ordering. The new way is also more consistent in how joins are reused.
Diffstat (limited to 'django/db/models/sql')
-rw-r--r--django/db/models/sql/expressions.py9
-rw-r--r--django/db/models/sql/query.py2
2 files changed, 7 insertions, 4 deletions
diff --git a/django/db/models/sql/expressions.py b/django/db/models/sql/expressions.py
index 374509914d..c809e25b49 100644
--- a/django/db/models/sql/expressions.py
+++ b/django/db/models/sql/expressions.py
@@ -1,14 +1,16 @@
from django.core.exceptions import FieldError
from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields import FieldDoesNotExist
+from django.db.models.sql.constants import REUSE_ALL
class SQLEvaluator(object):
- def __init__(self, expression, query, allow_joins=True):
+ def __init__(self, expression, query, allow_joins=True, reuse=REUSE_ALL):
self.expression = expression
self.opts = query.get_meta()
self.cols = []
self.contains_aggregate = False
+ self.reuse = reuse
self.expression.prepare(self, query, allow_joins)
def prepare(self):
@@ -50,9 +52,10 @@ class SQLEvaluator(object):
try:
field, source, opts, join_list, last, _ = query.setup_joins(
field_list, query.get_meta(),
- query.get_initial_alias(), False)
+ query.get_initial_alias(), self.reuse)
col, _, join_list = query.trim_joins(source, join_list, last, False)
-
+ if self.reuse is not None and self.reuse != REUSE_ALL:
+ self.reuse.update(join_list)
self.cols.append((node, (join_list[-1], col)))
except FieldDoesNotExist:
raise FieldError("Cannot resolve keyword %r into field. "
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 4cfb816958..b03465b402 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1096,7 +1096,7 @@ class Query(object):
value = value()
elif isinstance(value, ExpressionNode):
# If value is a query expression, evaluate it
- value = SQLEvaluator(value, self)
+ value = SQLEvaluator(value, self, reuse=can_reuse)
having_clause = value.contains_aggregate
for alias, aggregate in self.aggregates.items():