-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
Fixed #27021 -- Allowed lookup expressions in annotations, aggregations, and QuerySet.filter(). #14494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the patch Ian! We've had recent questions about this exact usage cases.
I think we should defer the decision around __gt__
and friends and focus on making Lookup
implement as much of the expression API as possible. That will not only pave the way for annotations but also direct usage in filter(...)
and friends which can be useful under certain circumstances e.g. https://groups.google.com/g/django-developers/c/iiOnxAn3vy4
10fd9d6
to
3175ca5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ian-Foote Great job, thanks 🚀
Release notes are missing. I would also
- add examples in the Query Expressions -> Some examples,
- add a short paragraph in the Built-in Expressions or Lookup docs 🤔
Can we add extra tests?
- combined lookups, e.g.
Exact(F('integer'), 42) | GreaterThan(F('integer'), 42)
, - using lookups directly in the
QuerySet.filter()
, e.g..filter(GreaterThan(F('integer'), 42))
, - using lookups in the
Queryset.alias()
.
4ae8d11
to
0e7ef74
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the adjustments Ian!
Note that the making django/django/db/models/sql/where.py Lines 189 to 209 in ed3af3f
|
@charettes I'm not clear what change you're suggesting in |
@Ian-Foote not a big deal and it can be handled in a following the PR. The idea is that e.g. (still untested) def resolve_expression(self, *args, **kwargs):
clone = self.clone()
clone.children = [
child.resolve_expression(*args, **kwargs) for child in clone.children
]
clone.resolved = True
return clone |
78ec728
to
f84c77c
Compare
@charettes I just tested that and got a bunch of errors. I spent a little time trying to debug, but decided to leave it for now. |
@Ian-Foote sounds good, thanks for having a look! |
f84c77c
to
22ba28c
Compare
@felixxm Good call on the combined expressions test - that needed some more tweaks to |
6b924a0
to
66aa6fd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ian-Foote Thanks for updates 👍 We're close 🚀. I pushed edits to fix failures on Oracle.
I would add a few more tests:
- using combined lookups directly in
QuerySet.filter()
, - using annotation of combined lookups in
QuerySet.filter()
, - using combined lookups/lookups in
QuerySet.aggregate()
.
a496b71
to
ca95e5a
Compare
@felixxm I added those extra tests and fixed another edge-case. I'm not sure quite how to get the docs to build correctly. |
25102e9
to
5281e6e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ian-Foote Thanks for updates 👍 I skipped one test on Oracle, pushed small edits to docs, and left comments. Can we add one more test 😉? i.e. using lookups directly in Case()
.
@felixxm I didn't look into details of the Oracle failure but lmk if you hit a wall. |
@Ian-Foote SELECT
"ANNOTATIONS_AUTHOR"."NAME",
CASE WHEN "ANNOTATIONS_BOOK"."ID" IS NULL THEN 0 ELSE MAX(T4."PAGES") END AS "MAX_PAGES"
FROM
"ANNOTATIONS_AUTHOR"
LEFT OUTER JOIN "ANNOTATIONS_BOOK" ON ("ANNOTATIONS_AUTHOR"."ID" = "ANNOTATIONS_BOOK"."CONTACT_ID")
LEFT OUTER JOIN "ANNOTATIONS_BOOK_AUTHORS" ON ("ANNOTATIONS_AUTHOR"."ID" = "ANNOTATIONS_BOOK_AUTHORS"."AUTHOR_ID")
LEFT OUTER JOIN "ANNOTATIONS_BOOK" T4 ON ("ANNOTATIONS_BOOK_AUTHORS"."BOOK_ID" = T4."ID")
WHERE "ANNOTATIONS_AUTHOR"."AGE" < 30
GROUP BY
"ANNOTATIONS_AUTHOR"."ID",
"ANNOTATIONS_AUTHOR"."NAME",
"ANNOTATIONS_AUTHOR"."AGE",
CASE WHEN "ANNOTATIONS_BOOK"."ID" IS NULL THEN 1 ELSE 0 END previously SELECT
"ANNOTATIONS_AUTHOR"."NAME",
CASE WHEN "ANNOTATIONS_BOOK"."ID" IS NULL THEN 0 ELSE MAX(T4."PAGES") END AS "MAX_PAGES"
FROM
"ANNOTATIONS_AUTHOR"
LEFT OUTER JOIN "ANNOTATIONS_BOOK" ON ("ANNOTATIONS_AUTHOR"."ID" = "ANNOTATIONS_BOOK"."CONTACT_ID")
LEFT OUTER JOIN "ANNOTATIONS_BOOK_AUTHORS" ON ("ANNOTATIONS_AUTHOR"."ID" = "ANNOTATIONS_BOOK_AUTHORS"."AUTHOR_ID")
LEFT OUTER JOIN "ANNOTATIONS_BOOK" T4 ON ("ANNOTATIONS_BOOK_AUTHORS"."BOOK_ID" = T4."ID")
WHERE "ANNOTATIONS_AUTHOR"."AGE" < 30
GROUP BY
"ANNOTATIONS_AUTHOR"."ID",
"ANNOTATIONS_AUTHOR"."NAME",
"ANNOTATIONS_AUTHOR"."AGE",
"ANNOTATIONS_BOOK"."ID" |
@Ian-Foote Do you have time to keep working on this? If not I can try to fix remaining comments. |
I had a look last night, but I didn't get anywhere (not having a working oracle setup was the biggest blocker). |
You could check other comments and leave an Oracle issue to me 🕵️ |
Yeah, I'll do that now. |
Great, thanks ❤️ |
@felixxm All yours ;) |
@Ian-Foote I fixed Oracle failure by adding |
@Ian-Foote Thanks for updates 👍 We are almost there 🏃 I rebased, squashed commits, fix tests failures on Oracle, added new tests Unfortunately |
Fixed 🥳 |
django/db/models/lookups.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if a crash similar to 170b006 can happen if the lhs is a Subquery
annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Challenge accepted 😉 I added two more tests test_filter_exists_lhs
and test_filter_subquery_lhs
.
…ns, and QuerySet.filter(). Thanks Hannes Ljungberg and Simon Charette for reviews. Co-authored-by: Mariusz Felisiak <[email protected]>
Thanks for getting this over the line @felixxm and thanks @charettes, @hannseman and @pauloxnet for the reviews! |
https://code.djangoproject.com/ticket/27021