﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
37330	Transform on an annotation alias crashes when output_field is not attached to a model	Kunal Kumar		"Applying a transform to an annotation alias raises AttributeError when the
annotation's output_field is not attached to a model:

{{{#!python
Book.objects.annotate(
    published=ExpressionWrapper(F(""pubdate""), output_field=DateField())
).values(""published__year"")
}}}

{{{
AttributeError: 'DateField' object has no attribute 'model'
}}}

Value(..., output_field=DateField()) fails the same way.

The same query works when the annotation's output_field happens to be a model
field, so the outcome depends on how the annotation was spelled rather than on
what it asks for:

|| annotation || .values(""a__year"") ||
|| annotate(a=F(""pubdate"")) || works ||
|| annotate(a=ExpressionWrapper(F(""pubdate""), output_field=DateField())) || AttributeError ||
|| annotate(a=Value(date(2026, 1, 1), output_field=DateField())) || AttributeError ||

Cause: names_to_path() resolves an annotation name to
self.annotations[name].output_field, which annotate() does not require to be
attached to a model. setup_joins()'s final_transformer() then calls
field.get_col(alias), and Field.get_col() dereferences self.model.

names_to_path() already anticipates this a few lines earlier:

{{{#!python
try:
    model = field.model._meta.concrete_model
except AttributeError:
    # QuerySet.annotate() may introduce fields that aren't attached to a model.
    model = None
}}}

An AttributeError escaping here also bypasses add_fields(), which catches
FieldError to build a helpful message.

Closest precedent found: #34921, same class of failure (an unsuccessful
self.model access on an unbound field, there in DateTimeField.to_python()).
I also searched for ""unbound annotation"", ""output_field model attribute"" and
""has no attribute model""; #36787 and #37248 are the nearest hits and neither
covers this path — both are closed/fixed with different symptoms.

Patch: https://github.com/django/django/pull/21914"	Bug	assigned	Uncategorized	dev	Normal				Unreviewed	1	0	0	0	0	0
