summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2007-12-03 21:10:51 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2007-12-03 21:10:51 +0000
commit57a4b882aeddc6f171d25808c8510bd09c410eff (patch)
tree0ceca14a2a08910c8dd81a711de45bcd47a8f42d
parentcc0078494e6a28c7c27f53748d6b16fafe0ca8fd (diff)
queryset-refactor: Fixed query disjunctions.
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6867 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/db/models/sql/query.py37
-rw-r--r--tests/regressiontests/queries/models.py2
2 files changed, 38 insertions, 1 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index fa1d10ed53..ad78c4dd47 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -8,6 +8,7 @@ all about the internals of models in order to get the information it needs.
"""
import copy
+import operator
import re
from django.utils.tree import Node
@@ -465,7 +466,7 @@ class Query(object):
result = []
for field in ordering:
if field == '?':
- result.append(self.connector.ops.random_function_sql())
+ result.append(self.connection.ops.random_function_sql())
continue
if isinstance(field, int):
if field < 0:
@@ -724,7 +725,32 @@ class Query(object):
# efficient at the database level.
self.promote_alias(join_list[-1][0])
+ if connector == OR:
+ # Some joins may need to be promoted when adding a new filter to a
+ # disjunction. We walk the list of new joins and where it diverges
+ # from any previous joins (ref count is 1 in the table list), we
+ # make the new additions (and any existing ones not used in the new
+ # join list) an outer join.
+ join_it = nested_iter(join_list)
+ table_it = iter(self.tables)
+ join_it.next(), table_it.next()
+ for join in join_it:
+ table = table_it.next()
+ if join == table and self.alias_map[join][ALIAS_REFCOUNT] > 1:
+ continue
+ self.promote_alias(join)
+ if table != join:
+ self.promote_alias(table)
+ break
+ for join in join_it:
+ self.promote_alias(join)
+ for table in table_it:
+ # Some of these will have been promoted from the join_list, but
+ # that's harmless.
+ self.promote_alias(table)
+
self.where.add([alias, col, field, lookup_type, value], connector)
+
if negate:
flag = False
for pos, null in enumerate(nullable):
@@ -1198,6 +1224,15 @@ def results_iter(cursor):
raise StopIteration
yield rows
+def nested_iter(nested):
+ """
+ An iterator over a sequence of sequences. Each element is returned in turn.
+ Only handles one level of nesting, since that's all we need here.
+ """
+ for seq in nested:
+ for elt in seq:
+ yield elt
+
def setup_join_cache(sender):
"""
The information needed to join between model fields is something that is
diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py
index 14ed0bb3b1..9f55f277ec 100644
--- a/tests/regressiontests/queries/models.py
+++ b/tests/regressiontests/queries/models.py
@@ -196,6 +196,8 @@ Bug #2080, #3592
[<Author: a1>, <Author: a3>]
>>> Author.objects.filter(Q(name='a3') | Q(item__name='one'))
[<Author: a1>, <Author: a3>]
+>>> Author.objects.filter(Q(item__name='three') | Q(report__name='r3'))
+[<Author: a2>]
Bug #6074
Merging two empty result sets shouldn't leave a queryset with no constraints