Changes between Initial Version and Version 3 of Ticket #36405


Ignore:
Timestamp:
May 22, 2025, 6:01:50 AM (3 months ago)
Author:
Adam Johnson
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #36405

    • Property Cc Chris M Simon Charette added
    • Property Owner set to Adam Johnson
    • Property Triage Stage UnreviewedAccepted
    • Property Status newassigned
    • Property Has patch set
    • Property Version dev5.2
  • Ticket #36405 – Description

    initial v3  
    1 While fixing #36404, I spotted the same mistake had been made for the newly added `Aggregate.order_by` from #35444.
     1While fixing #36404, I spotted the same mistake had been made for `Aggregate.order_by` (on `main`, from #35444), which was previously the PostgreSQL-specific `OrderableAggMixin.order_by` (on 5.2).
     2
     3The issue is reproduced ​in [https://github.com/adamchainz/django-ticket-36408 this example project], with models:
     4
     5{{{#!python
     6from django.db import models
     7
     8
     9class Book(models.Model):
     10    position = models.IntegerField()
     11
     12
     13class Chapter(models.Model):
     14    book = models.ForeignKey(Book, on_delete=models.CASCADE)
     15}}}
     16
     17And `QuerySet`:
     18
     19{{{#!python
     20from django.contrib.postgres.aggregates import ArrayAgg
     21from django.db.models import OuterRef, Subquery
     22
     23from example.models import Book, Chapter
     24
     25Book.objects.annotate(
     26    chapter_ids=Subquery(
     27        Chapter.objects.annotate(
     28            ids=ArrayAgg(
     29                "id",
     30                order_by=[OuterRef("position")],
     31            )
     32        ).values("ids")[:1]
     33    )
     34)
     35}}}
     36
     37This error occurs:
     38
     39{{{
     40$ python t.py
     41Traceback (most recent call last):
     42    File "/.../t.py", line 15, in <module>
     43    Chapter.objects.annotate(
     44    ~~~~~~~~~~~~~~~~~~~~~~~~^
     45        ids=ArrayAgg(
     46        ^^^^^^^^^^^^^
     47    ...<2 lines>...
     48        )
     49        ^
     50    ).values("ids")[:1]
     51    ^
     52    File "/.../django/db/models/manager.py", line 87, in manager_method
     53    return getattr(self.get_queryset(), name)(*args, **kwargs)
     54            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
     55    File "/.../django/db/models/query.py", line 1647, in annotate
     56    return self._annotate(args, kwargs, select=True)
     57            ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
     58    File "/.../django/db/models/query.py", line 1699, in _annotate
     59    clone.query.add_annotation(
     60    ~~~~~~~~~~~~~~~~~~~~~~~~~~^
     61        annotation,
     62        ^^^^^^^^^^^
     63        alias,
     64        ^^^^^^
     65        select=select,
     66        ^^^^^^^^^^^^^^
     67    )
     68    ^
     69    File "/.../django/db/models/sql/query.py", line 1218, in add_annotation
     70    annotation = annotation.resolve_expression(self, allow_joins=True, reuse=None)
     71    File "/.../django/contrib/postgres/aggregates/mixins.py", line 33, in resolve_expression
     72    return super().resolve_expression(*args, **kwargs)
     73            ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
     74    File "/.../django/db/models/aggregates.py", line 63, in resolve_expression
     75    c = super().resolve_expression(query, allow_joins, reuse, summarize)
     76    File "/.../django/db/models/expressions.py", line 300, in resolve_expression
     77    expr.resolve_expression(query, allow_joins, reuse, summarize)
     78    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     79    File "/.../django/db/models/expressions.py", line 300, in resolve_expression
     80    expr.resolve_expression(query, allow_joins, reuse, summarize)
     81    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     82    File "/.../django/db/models/expressions.py", line 941, in resolve_expression
     83    col = super().resolve_expression(*args, **kwargs)
     84    File "/.../django/db/models/expressions.py", line 902, in resolve_expression
     85    return query.resolve_ref(self.name, allow_joins, reuse, summarize)
     86            ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     87    File "/.../django/db/models/sql/query.py", line 2049, in resolve_ref
     88    join_info = self.setup_joins(
     89        field_list, self.get_meta(), self.get_initial_alias(), can_reuse=reuse
     90    )
     91    File "/.../django/db/models/sql/query.py", line 1900, in setup_joins
     92    path, final_field, targets, rest = self.names_to_path(
     93                                        ~~~~~~~~~~~~~~~~~~^
     94        names[:pivot],
     95        ^^^^^^^^^^^^^^
     96    ...<2 lines>...
     97        fail_on_missing=True,
     98        ^^^^^^^^^^^^^^^^^^^^^
     99    )
     100    ^
     101    File "/.../django/db/models/sql/query.py", line 1805, in names_to_path
     102    raise FieldError(
     103    ...<2 lines>...
     104    )
     105django.core.exceptions.FieldError: Cannot resolve keyword 'position' into field. Choices are: book, book_id, id
     106}}}
     107
     108This error again bisects to e306687a3a5507d59365ba9bf545010e5fd4b2a8. The cause is similar: duplicate `OuterRef` resolution occurs due to a clause left in `OrderableAggMixin.resolve_expression()`.
Back to Top