From 90b86291d022a09031d1df397d7aaebc30e435f7 Mon Sep 17 00:00:00 2001 From: Anssi Kääriäinen Date: Thu, 22 Nov 2012 20:27:28 +0200 Subject: 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. --- django/db/models/sql/expressions.py | 9 ++++++--- django/db/models/sql/query.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'django/db/models/sql') 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(): -- cgit v1.3