Opened 4 years ago
Last modified 6 months ago
#31714 new Cleanup/optimization
ResolvedOuterRef object has no get_lookup
Reported by: | BorisZZZ | Owned by: | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 3.0 |
Severity: | Normal | Keywords: | |
Cc: | Denis Verbin | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
This looks like an issue very similar to #28621, only in this case the issue is cause by using the annotation on the LHS of a filter.
For example,
class A(models.Model): r = IntegerRangeField() A.objects.annotate(x=OuterRef("x")).filter(x__contained_in=F("r"))
will result in the following stack trace:
Traceback (most recent call last): ... File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 904, in filter return self._filter_or_exclude(False, *args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 923, in _filter_or_exclude clone.query.add_q(Q(*args, **kwargs)) File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1350, in add_q clause, _ = self._add_q(q_object, self.used_aliases) File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1377, in _add_q child_clause, needed_inner = self.build_filter( File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1267, in build_filter condition = self.build_lookup(lookups, reffed_expression, value) File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1153, in build_lookup lookup_class = lhs.get_lookup(lookup_name) AttributeError: 'ResolvedOuterRef' object has no attribute 'get_lookup'
Change History (7)
comment:1 by , 4 years ago
Triage Stage: | Unreviewed → Accepted |
---|---|
Type: | Bug → Cleanup/optimization |
comment:2 by , 3 years ago
Cc: | added |
---|
I'm faced with the same issue (#32043) and hope it will be fixed.
comment:3 by , 2 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:4 by , 2 years ago
As a workaround OuterRef
can be wrapped in ExpressionWrapper
, e.g.
A.objects.annotate( x=ExpressionWrapper(OuterRef("x"), output_field=IntegerRangeField()) ).filter(x__contained_in=F("r"))
comment:5 by , 19 months ago
filtered_relation.tests.FilteredRelationTests.test_conditional_expression_with_subquery
should work when this ticket is fixed:
def test_conditional_expression_with_subquery(self): self.assertSequenceEqual( Author.objects.annotate( book_editor=FilteredRelation( "book__editor", condition=Q(Exists( Editor.objects.annotate( author_name=OuterRef('name'), ).filter( author_name__istartswith=F('name'), ) )), ), ), [self.author1], )
comment:6 by , 19 months ago
Owner: | removed |
---|---|
Status: | assigned → new |
comment:7 by , 6 months ago
FWIW I stumbled upon another user running into the same problem but for _output_field_or_none
.
I think that an appropriate solution here could be to
- Allow an
output_field
to be specified toOuterRef
and percolate toResolvedOuterRef
. It's a common pattern forExpression
-like to accept this kind of parameter. - At the time
ResolvedOuterRef
performs its final resolution in the outer query error out if there is a mismatch ofoutput_field
(type only should be enough) between what was explicitly specified and the resolved expression one.
While the ExpressionWrapper
solution works I think it's a big leap for users to figure out they should be using it when they encounter a seemingly random AttributeError
.
I think we could error out which a more appropriate message but it will be very hard to make the above queryset work since
OuterRef
cannot be resolved to a properoutput_field
until its queryset gets annotated to an outer query. I guess we could allow anoutput_field
to be specified onOuterRef
initialization to allowfilter
to reference it before it's resolved to aCol
.