summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--django/db/models/sql/where.py3
-rw-r--r--docs/ref/models/querysets.txt4
-rw-r--r--tests/regressiontests/extra_regress/tests.py31
4 files changed, 36 insertions, 3 deletions
diff --git a/AUTHORS b/AUTHORS
index 0af0c7961e..fc3cb93406 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -326,6 +326,7 @@ answer newbie questions, and generally made Django that much better:
lcordier@point45.com
Jeong-Min Lee <falsetru@gmail.com>
Tai Lee <real.human@mrmachine.net>
+ Adrien Lemaire <lemaire.adrien@gmail.com>
Christopher Lenz <http://www.cmlenz.net/>
lerouxb@gmail.com
Piotr Lewandowski <piotr.lewandowski@gmail.com>
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index 2bd705dd60..0bc3638b80 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -281,7 +281,8 @@ class ExtraWhere(object):
self.params = params
def as_sql(self, qn=None, connection=None):
- return " AND ".join(self.sqls), tuple(self.params or ())
+ sqls = ["(%s)" % sql for sql in self.sqls]
+ return " AND ".join(sqls), tuple(self.params or ())
class Constraint(object):
"""
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index e25bea0e69..b20c6e34e5 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -968,11 +968,11 @@ of the arguments is required, but you should use at least one of them.
Example::
- Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])
+ Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
...translates (roughly) into the following SQL::
- SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);
+ SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
Be careful when using the ``tables`` parameter if you're specifying
tables that are already used in the query. When you add extra tables
diff --git a/tests/regressiontests/extra_regress/tests.py b/tests/regressiontests/extra_regress/tests.py
index 67efb428dd..3fcafef5de 100644
--- a/tests/regressiontests/extra_regress/tests.py
+++ b/tests/regressiontests/extra_regress/tests.py
@@ -313,3 +313,34 @@ class ExtraRegressTests(TestCase):
TestObject.objects.extra(where=["id > %s"], params=[obj.pk]),
['<TestObject: TestObject: first,second,third>']
)
+
+ def test_regression_17877(self):
+ """
+ Ensure that extra WHERE clauses get correctly ANDed, even when they
+ contain OR operations.
+ """
+ # Test Case 1: should appear in queryset.
+ t = TestObject(first='a', second='a', third='a')
+ t.save()
+ # Test Case 2: should appear in queryset.
+ t = TestObject(first='b', second='a', third='a')
+ t.save()
+ # Test Case 3: should not appear in queryset, bug case.
+ t = TestObject(first='a', second='a', third='b')
+ t.save()
+ # Test Case 4: should not appear in queryset.
+ t = TestObject(first='b', second='a', third='b')
+ t.save()
+ # Test Case 5: should not appear in queryset.
+ t = TestObject(first='b', second='b', third='a')
+ t.save()
+ # Test Case 6: should not appear in queryset, bug case.
+ t = TestObject(first='a', second='b', third='b')
+ t.save()
+
+ self.assertQuerysetEqual(
+ TestObject.objects.extra(
+ where=["first = 'a' OR second = 'a'", "third = 'a'"],
+ ),
+ ['<TestObject: TestObject: a,a,a>', '<TestObject: TestObject: b,a,a>']
+ )