diff options
| author | Anssi Kääriäinen <akaariai@gmail.com> | 2012-11-22 20:27:28 +0200 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2012-11-23 19:53:04 +0200 |
| commit | 90b86291d022a09031d1df397d7aaebc30e435f7 (patch) | |
| tree | d0264a1fee77724db1660d8ac807c4689189051d /django | |
| parent | 7b9a1fb9649d169f4ec0e539c4901c66b0f5ebb6 (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')
| -rw-r--r-- | django/db/models/sql/expressions.py | 9 | ||||
| -rw-r--r-- | django/db/models/sql/query.py | 2 |
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(): |
