Ticket #17877: t17877.diff

File t17877.diff, 3.0 KB (added by Adrien Lemaire, 6 years ago)

patch + doc + tests

  • django/db/models/sql/where.py

    diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
    index 2bd705d..cf44153 100644
    a b class ExtraWhere(object): 
    281281        self.params = params
    282282
    283283    def as_sql(self, qn=None, connection=None):
    284         return " AND ".join(self.sqls), tuple(self.params or ())
     284        sqls = ["(%s)" % e for e in self.sqls]
     285        return " AND ".join(sqls), tuple(self.params or ())
    285286
    286287class Constraint(object):
    287288    """
  • docs/ref/models/querysets.txt

    diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
    index e25bea0..b20c6e3 100644
    a b of the arguments is required, but you should use at least one of them. 
    968968
    969969  Example::
    970970
    971       Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])
     971      Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    972972
    973973  ...translates (roughly) into the following SQL::
    974974
    975       SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);
     975      SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
    976976
    977977  Be careful when using the ``tables`` parameter if you're specifying
    978978  tables that are already used in the query. When you add extra tables
  • tests/regressiontests/extra_regress/tests.py

    diff --git a/tests/regressiontests/extra_regress/tests.py b/tests/regressiontests/extra_regress/tests.py
    index 67efb42..e69e17d 100644
    a b class ExtraRegressTests(TestCase): 
    313313               TestObject.objects.extra(where=["id > %s"], params=[obj.pk]),
    314314            ['<TestObject: TestObject: first,second,third>']
    315315        )
     316
     317    def test_regression_17877(self):
     318        """
     319        Regression for #17877: When chaining several elements including OR
     320        operations, the result was wrong due to higher priority for AND
     321        operatoins. Fix is to wrap all element in parenthesis
     322        """
     323        # Test Case 1: should appear in queryset.
     324        t = TestObject(first='a', second='a', third='a')
     325        t.save()
     326        # Test Case 2: should appear in queryset.
     327        t = TestObject(first='b', second='a', third='a')
     328        t.save()
     329        # Test Case 3: should not appear in queryset, bug case.
     330        t = TestObject(first='a', second='a', third='b')
     331        t.save()
     332        # Test Case 4: should not appear in queryset.
     333        t = TestObject(first='b', second='a', third='b')
     334        t.save()
     335        # Test Case 5: should not appear in queryset.
     336        t = TestObject(first='b', second='b', third='a')
     337        t.save()
     338        # Test Case 6: should not appear in queryset, bug case.
     339        t = TestObject(first='a', second='b', third='b')
     340        t.save()
     341
     342        self.assertQuerysetEqual(
     343            TestObject.objects.extra(
     344                where=["first = 'a' OR second = 'a'", "third = 'a'"],
     345            ),
     346            ['<TestObject: TestObject: a,a,a>', '<TestObject: TestObject: b,a,a>']
     347        )
Back to Top