#34803: Nested OuterRef can raise AttributeError: 'OuterRef' object has no attribute 'contains_over_clause' -------------------------------------+------------------------------------- Reporter: | Owner: nobody pierrenicolasr | Type: Bug | Status: new Component: Database | Version: 4.2 layer (models, ORM) | Severity: Normal | Keywords: Triage Stage: | Has patch: 0 Unreviewed | Needs documentation: 0 | Needs tests: 0 Patch needs improvement: 0 | Easy pickings: 0 UI/UX: 0 | -------------------------------------+------------------------------------- Porting our application from Django 3 to 4, we're seeing exception raised in complex queries using nested OuterRef
{{{ File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/query.py", line 1436, in filter return self._filter_or_exclude(False, args, kwargs) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/query.py", line 1454, in _filter_or_exclude clone._filter_or_exclude_inplace(negate, args, kwargs) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/query.py", line 1461, in _filter_or_exclude_inplace self._query.add_q(Q(*args, **kwargs)) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/query.py", line 1545, in add_q clause, _ = self._add_q(q_object, self.used_aliases) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/query.py", line 1576, in _add_q child_clause, needed_inner = self.build_filter( File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/query.py", line 1435, in build_filter value = self.resolve_lookup_value(value, can_reuse, allow_joins) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/query.py", line 1204, in resolve_lookup_value value = value.resolve_expression( File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/query.py", line 1923, in resolve_expression query = self.query.resolve_expression(*args, **kwargs) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/query.py", line 1145, in resolve_expression clone.where.resolve_expression(query, *args, **kwargs) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/where.py", line 278, in resolve_expression clone._resolve_node(clone, *args, **kwargs) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/where.py", line 270, in _resolve_node cls._resolve_node(child, query, *args, **kwargs) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/where.py", line 274, in _resolve_node node.rhs = cls._resolve_leaf(node.rhs, query, *args, **kwargs) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/sql/where.py", line 263, in _resolve_leaf expr = expr.resolve_expression(query, *args, **kwargs) File "/usr/local/filewave/python/lib/python3.10/site- packages/django/db/models/expressions.py", line 862, in resolve_expression if col.contains_over_clause: AttributeError: 'OuterRef' object has no attribute 'contains_over_clause' }}} Looking at code, the issue seems to be the following: {{{ class ResolvedOuterRef(F): """ An object that contains a reference to an outer query. In this case, the reference to the outer query has been resolved because the inner query has been used as a subquery. """ contains_aggregate = False contains_over_clause = False def as_sql(self, *args, **kwargs): raise ValueError( "This queryset contains a reference to an outer query and may " "only be used in a subquery." ) def resolve_expression(self, *args, **kwargs): col = super().resolve_expression(*args, **kwargs) if col.contains_over_clause: raise NotSupportedError( f"Referencing outer query window expression is not supported: " f"{self.name}." ) }}} In case of OuterRef(OuterRef( "field" )), `col = super().resolve_expression(*args, **kwargs)` will use: {{{ class OuterRef(F): contains_aggregate = False def resolve_expression(self, *args, **kwargs): if isinstance(self.name, self.__class__): return self.name return ResolvedOuterRef(self.name) }}} so self.name is an OuterRef, then it returns it directly, and then ` if col.contains_over_clause:` fails because col.contains_over_clause is not defined for OuterRef. Looks like adding col.contains_over_clause=False to class OuterRef solves the issue - or checking if object col.contains_over_clause. -- Ticket URL: <https://code.djangoproject.com/ticket/34803> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/0107018a416556d4-51a6cd87-8ec6-4c3c-b7b3-fb8d8e7224b2-000000%40eu-central-1.amazonses.com.