Repository navigation
Fixed #37115, Refs #5929 -- Added a CompositeField expression to support multi-column subqueries. - #21636
Fixed #37115, Refs #5929 -- Added a CompositeField expression to support multi-column subqueries.#21636p-r-a-v-i-n wants to merge 97 commits into
Conversation
| clause = WhereNode([condition], connector=AND) | ||
| if ( | ||
| current_negated | ||
| and condition.lookup_name != "isnull" | ||
| and condition.rhs is not None | ||
| and self._expression_contains_nullable_subquery_column(condition.lhs) | ||
| ): | ||
| lookup_class = condition.lhs.get_lookup("isnull") | ||
| clause.add(lookup_class(condition.lhs, False), AND) |
There was a problem hiding this comment.
This change is for the case when we have something
inner --> which don't have email = 'bob@mail.com'. but in the outer query if we are doing
outer --> .exclude(info__email='bob@mail.com') in this case
we are appending here is_null=False condition in the where node. so we should get explicit true or false. not unknown.
Before:
WHERE NOT ( 'info'.email == 'bob@mail.com'') but info.email is NULL, so it becaming
WHERE NOT ( null == 'bob@mail.com' ) -->
WHERE NOT UNKNOWN will remove the outer row.
After:
NULL == "'bob@mail.com" --> unknown
AND
NULL IS NOT NULL --> FALSE
UNKOWN FALSE --> FALSE
NOT FALSE --> TRUE --> so the outer row is preserved.
I may sound unclear here , please don't hesitate to ask again.
|
#21496 (comment) and Jacob's suggestion
helped me to come up with this idea. Just high-level overview of the current approach ( may be I should have put this into the PR body ): We are not changing the existing behavior for single-column subqueries. We trigger this new logic only when these If it is a The After that: this way, the inner multi-column query is added to the |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
jacobtylerwalls
left a comment
There was a problem hiding this comment.
This simpler version looks promising!
| class CompositeField(Field): | ||
| is_composite = True | ||
|
|
||
| def __init__(self, **kwargs): |
There was a problem hiding this comment.
As on the previous PR, I think we should add support for *args without names. I suppose we could do this in another PR that adds test cases for Func() subclasses instead of Subquery, as I imagine that to be the use case for anonymous args.
There was a problem hiding this comment.
See #21636 (comment) for more discussion about *args.
19d7423 to
05fa1eb
Compare
|
buildbot, test on oracle. |
jacobtylerwalls
left a comment
There was a problem hiding this comment.
Did a manual test against a PR for djangoproject.com, and I have a couple of observations.
|
|
||
| These subfields can be selected, filtered, annotated, and ordered in the same | ||
| way as model fields. See :ref:`using-multi-column-subqueries` for more details. | ||
|
|
There was a problem hiding this comment.
In a follow-up PR, we could walk through the example from jacobtylerwalls/djangoproject.com@219e530 in the contrib.postgres docs for SearchHeadline, and show an example like this:
Since SearchHeadline can be expensive to calculate, the query below avoids
annotating it on all results before the limit is taken, and also avoids
re-expressing the rank::
subquery = (
Product.objects
.annotate(rank=SearchRank(...))
.values("pk", "rank")
.order_by("-rank", "pk")
)
query = (
Product.objects
.alias(ranked=subquery[:10])
.filter(pk__in=F("ranked__pk")
.annotate(headline=SearchHeadline(...))
.order_by("-ranked__rank", "pk")
)or similar.
If we do that, then we could possibly link to that here, idk.
(But we can leave for a follow-up, to give others a chance to weigh in.)
There was a problem hiding this comment.
I liked it. That will add more merits (in my POV).
637cbe3 to
2acd3cd
Compare
jacobtylerwalls
left a comment
There was a problem hiding this comment.
I really appreciate the incremental commits including test cases with each change, nice work on that!
I did another holistic review, and then my plan is to look a little closer at the join machinery parts to see if we can squeeze out any simplifications.
| ) | ||
|
|
||
|
|
||
| class CompositeFieldOutputFieldTests(SimpleTestCase): |
There was a problem hiding this comment.
You might burst this file into modules. You don't have to use as many as tests/composite_pk did, but it's probably good to have more than just one module.
There was a problem hiding this comment.
Maybe we can hold this comment until the end, since I just praised all your atomic commits with tests 🤣
ed7559a to
b7c33e5
Compare
This reverts commit a2efb67.
349539b to
11869c9
Compare
Uncovered lines in changed filesNote: Missing lines are warnings only. Some database-specific lines may not be measured. More information |
Trac ticket number
ticket-37115
ticket-5929
Branch description
This PR Introduces a CompositeField to support subqueries which return multi-cols.
Currently Django ORM does not have internal machinery to decide the
output_fieldof subqueries which have multi-columns in their output.CompositeFieldwill resolveoutput_fieldfor such subqueries.Scope of this PR:
OuterRef) subquery not supported .References:
AI Assistance Disclosure (REQUIRED)
2. I also took help to write documentation part.
Checklist
mainbranch.