Support annotations and joins in F() #1761
Open
+664
−242
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
This PR:
F()
, e.g.F("author__name")
that automatically introduces joins to the queryF()
, e.g.IntFields.annotate(intnum_plus_1=F("intnum") + 1).annotate(intnum_plus_2=F("intnum_plus_1") + 1)
In order to achieve that, the following implementation details changed
Expression.resolve
was unified to always return aResolveResult
. Previously it could have been either a tuple or dictionary.F
was changed to be anExpression
instead of pypika'sField
. This allowed to move theF
's resolution code insideF.resolve
and simplify the resolution code in general becauseF
can be treated as otherExpression
s.CombinedExpression
was introduced to handle arithmetic operations onF()
, e.g.F("a") + 1
. It was inspired by Django's CombinedExpression and replaces pypika's arithmetic.CombinedExpression
is a child ofExpression
, so it can be resolved without knowing the exact type of the object as opposed to pypika'sArithmeticExpression
that was used previosly.As part of this PR, I had to change how custom functions can be defined. It changed from
to
Effectively now custom functions are supposed to be a tortoise
Function
, not a Pypika'sFunction
. The change had to be done because the Pypika'sFunction
is no longer compatible withF
and, frankly, having the interface that accepts both Pypika's functions and tortoise functions is a bit messy and makes the code quite convoluted.Motivation and Context
This introduces functionality supported by Django but also there is a clear demand for these features in the tortoise community. The following issues should be fixed by this PR
Model.annotate(...).update(...)
not working #1703How Has This Been Tested?
Checklist: