Opened 5 years ago
Last modified 18 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 , 5 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|---|
| Type: | Bug → Cleanup/optimization |
comment:2 by , 4 years ago
| Cc: | added |
|---|
I'm faced with the same issue (#32043) and hope it will be fixed.
comment:3 by , 3 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:4 by , 3 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 , 3 years 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 , 3 years ago
| Owner: | removed |
|---|---|
| Status: | assigned → new |
comment:7 by , 18 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_fieldto be specified toOuterRefand percolate toResolvedOuterRef. It's a common pattern forExpression-like to accept this kind of parameter. - At the time
ResolvedOuterRefperforms 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
OuterRefcannot be resolved to a properoutput_fielduntil its queryset gets annotated to an outer query. I guess we could allow anoutput_fieldto be specified onOuterRefinitialization to allowfilterto reference it before it's resolved to aCol.