#36480: FieldError when referencing a nonexistent alias provides less information
than nonexistent annotation
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Type:
| Cleanup/optimization
Status: new | Component: Database
| layer (models, ORM)
Version: dev | Severity: Normal
Keywords: typo | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
When migrating some querysets to use `.alias()` rather than `.annotate()`
for
[
https://docs.djangoproject.com/en/5.2/ref/models/querysets/#django.db.models.query.QuerySet.alias
performance purposes], I noticed when you typo a reference to an argument
to `.alias()`, the hint provided by the `FieldError` does not include it.
(Whereas when using `.annotate()`, the `FieldError` hint ''does'' include
what you meant.)
{{{#!py
In [1]: from django.db.models import F
In [2]: Tile.objects.alias(my_alias=F("pk")).order_by("typo") # notice
"my_alias" missing from hint
---------------------------------------------------------------------------
FieldError Traceback (most recent call
last)
Cell In[2], line 1
----> 1 Tile.objects.alias(my_alias=F("pk")).order_by("typo")
File ~/py313/lib/python3.13/site-packages/django/db/models/query.py:1722,
in QuerySet.order_by(self, *field_names)
1720 obj = self._chain()
1721 obj.query.clear_ordering(force=True, clear_default=False)
-> 1722 obj.query.add_ordering(*field_names)
1723 return obj
File ~/py313/lib/python3.13/site-
packages/django/db/models/sql/query.py:2291, in Query.add_ordering(self,
*ordering)
2288 continue
2289 # names_to_path() validates the lookup. A descriptive
2290 # FieldError will be raise if it's not.
-> 2291 self.names_to_path(item.split(LOOKUP_SEP), self.model._meta)
2292 elif not hasattr(item, "resolve_expression"):
2293 errors.append(item)
File ~/py313/lib/python3.13/site-
packages/django/db/models/sql/query.py:1805, in Query.names_to_path(self,
names, opts, allow_many, fail_on_missing)
1797 if pos == -1 or fail_on_missing:
1798 available = sorted(
1799 [
1800 *get_field_names_from_opts(opts),
(...)
1803 ]
1804 )
-> 1805 raise FieldError(
1806 "Cannot resolve keyword '%s' into field. "
1807 "Choices are: %s" % (name, ", ".join(available))
1808 )
1809 break
1810 # Check if we need any joins for concrete inheritance cases (the
1811 # field lives in parent, but we are currently in one of its
1812 # children)
FieldError: Cannot resolve keyword 'typo' into field. Choices are: child,
data, file, geojsongeometry, nodegroup, nodegroup_id, parenttile,
parenttile_id, provisionaledits, resourceinstance, resourceinstance_id,
resxres, sortorder, tileid, vwannotation
}}}
----
I'm seeing this fixed with the following, but I stopped short of
investigating the blame to see if it was explored before. (A contributor
might have a look into that and report back?)
{{{#!diff
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 20dbf7cfaa..3d9f39458b 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1820,7 +1820,7 @@ class Query(BaseExpression):
available = sorted(
[
*get_field_names_from_opts(opts),
- *self.annotation_select,
+ *self.annotations,
*self._filtered_relations,
]
)
}}}
(For anybody who followed #36380, you'll be glad to hear `.alias()` let me
prune my hundreds of useless annotations 😅)
--
Ticket URL: <
https://code.djangoproject.com/ticket/36480>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.