Opened 15 months ago
Closed 15 months ago
#34786 closed Uncategorized (invalid)
Multiple Q objects in the same .filter() behave oddly with ManyToMany relationships
Reported by: | Jon Janzen | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 4.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I found something odd, this may be intentional behavior (if undocumented, AFAICT) or might be covered by another bug report. If so, I apologize for the dupe.
Basically, I would have expected the following to behave the same, but they do not:
Test.objects.filter(Q(tags=1)).filter(Q(tags=2)) Test.objects.filter(Q(tags=1), Q(tags=2))
(Where Test is some model with a Many2Many relationship called "tags" and the model on the other end of "tags" has 2 objects with IDs 1 and 2)
In my testing, the first query returns an "and" of the results, that is, only Test objects that are tagged with BOTH Tag 1 and Tag 2, while the second query returns no results. Furthermore, Test.objects.filter(Q(tags=1) & Q(tags=2))
also returns no results.
I have a system that converts GitHub-like query expressions (e.g. "is:pr is:open author:bigfootjon") into Django ORM and it previously made a call like ModelToSearch.objects.filter(*q_expressions)
until I hit this "bug" when I was adding support for searching via a ManyToMany field. Now I just loop over q_expressions
and call .filter()
repeatedly so I'm not blocked by this, but I thought it was odd. I checked the docs (https://docs.djangoproject.com/en/4.2/topics/db/queries/) and didn't see anything about this edge-case mentioned.
I've prepared a test-project that reproduces this behavior with instructions on how to show the weirdness: https://github.com/bigfootjon/djangoqbugreport
(In that repo I specify testing against Django 4.2.4, but this also reproduces on Django 5.0 at commit 517d3bb4dd17e9c51690c98d747b86a0ed8b2fbf
aka Django==5.0.dev20230819082943
)
I'm not sure whether to classify this as a bug or not, but if it is not a bug I think it should be documented (somehow, I don't quite understand the problem well enough myself to document it).
I'm afraid I don't quite have the ORM terminology to express this bug clearly so I apologize if this isn't clear in any way, I'm happy to answer questions.
This is not strictly related with
Q()
objects and it's a documented behavior (check out #27936).