Opened 48 minutes ago
#37330 assigned Bug
Transform on an annotation alias crashes when output_field is not attached to a model
| Reported by: | Kunal Kumar | Owned by: | |
|---|---|---|---|
| Component: | Uncategorized | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Applying a transform to an annotation alias raises AttributeError when the
annotation's output_field is not attached to a model:
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("ayear") |
| 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:
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.