Opened 17 years ago
Closed 17 years ago
#4289 closed (fixed)
Misbehaving Q objects
Reported by: | Ben Khoo | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Keywords: | Q Oracle sqlite OR qs-rf-fixed | |
Cc: | mir@… | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Hi,
The following ticket will try to highlight a problem that I have found when using the 'OR' operator on Q objects in the boulder-oracle-sprint branch.
My model looks like this.
class Test(models.Model): num = models.IntegerField() def __str__(self): return 'num=%d'%self.num
The following code will highlight the bug:
In [1]: from testapp.models import * In [2]: from django.db.models import Q In [3]: for i in [4,8,12]: ...: Test(num=i).save() ...: In [4]: Test.objects.filter(num__lt=4) Out[4]: [] In [5]: Test.objects.filter(num__gt=8, num__lt=12) Out[5]: [] In [6]: Test.objects.filter(Q(num__lt = 4) | Q(num__gt=8, num__lt=12)) Out[6]: [<Test: num=12>, <Test: num=4>, <Test: num=8>] In [7]: Test.objects.filter(Q(num__gt=8, num__lt=12) | Q(num__lt = 4)) Out[7]: [<Test: num=12>, <Test: num=4>, <Test: num=8>] In [8]: Test.objects.filter(Q(num__gt=8) & Q(num__lt=12) | Q(num__lt = 4)) Out[8]: []
Lines 6 and 7 illustrate the bug.
The query appears to indicate that there are three Test objects where 'num' is less than 4 or, greater than 8 and less than 12.
Lines 4 and 5 show that no such object should exist.
Line 8 shows how I would expect the query to run.
The following is the formated (but otherwise unmodified) SQL query produced by django.
SELECT * FROM "TESTAPP_TEST" WHERE (("TESTAPP_TEST"."NUM" < 4 OR "TESTAPP_TEST"."NUM" > 8 OR "TESTAPP_TEST"."NUM" < 12))
The issue is that the second 'OR' operator should be an AND operator. Also for the sake of safety/sanity I feel that queries specified within the Q objects should also be surrounded by a bracket.
The corrected query should read
SELECT * FROM "TESTAPP_TEST" WHERE ((("TESTAPP_TEST"."NUM" < 4) OR ("TESTAPP_TEST"."NUM" > 8 AND "TESTAPP_TEST"."NUM" < 12)))
Regards
Ben
Change History (10)
follow-up: 3 comment:1 by , 17 years ago
comment:2 by , 17 years ago
Cc: | added |
---|
comment:3 by , 17 years ago
Replying to mtredinnick:
This is almost certainly the same problem we have with some Q() constructions on trunk as well and is one of the motivations behind refactoring the QuerySet class.
Confirmed. I tried this against the sqlite3 backend in the trunk and got the same results.
comment:4 by , 17 years ago
Component: | Uncategorized → Database wrapper |
---|---|
Description: | modified (diff) |
Keywords: | sqlite added |
Owner: | changed from | to
Version: | other branch → SVN |
comment:5 by , 17 years ago
I retested trunk during the "worldwide sprint," and the same behavior persists against Oracle and sqlite3 backends, just FYI.
comment:6 by , 17 years ago
Keywords: | qs-rf added |
---|
comment:7 by , 17 years ago
Summary: | Misbehaving Q objects in boulder-oracle-sprint branch → Misbehaving Q objects |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:8 by , 17 years ago
comment:9 by , 17 years ago
Keywords: | qs-rf-fixed added; qs-rf removed |
---|
comment:10 by , 17 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
(In [7477]) Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
This is almost certainly the same problem we have with some Q() constructions on trunk as well and is one of the motivations behind refactoring the QuerySet class.