#31420: Using SimpleLazyObject with a nested subquery annotation fails.
-------------------------------------+-------------------------------------
Reporter: Jordan Ephron | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 3.0
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: simplelazyobject, | Triage Stage: Accepted
queryset, subquery |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Simon Charette):
Alright so here's what's happening here.
When the most outer `filter(owner_user=user)` call is made the lookup
logic tries to resolve `owner_user`'s `output_field` in order to
`get_lookup('exact')` on it. `owner_user` points to `Subquery(owner_user)`
and it's `.output_field` is `self.query.output_field`. Since
`.values('owner_user')` refers to `Subquery(C.objects.values('owner'))`
which refers to `self.query.output_field` which refers to a column mapping
to a `Col` referencing `C.owner` the actual outer most
`filter(owner_user=user)` left hand side output field is whatever
`sql.Query.output_field` returns for a selected field.
This happens to be `Col.field`
https://github.com/django/django/blob/89032876f427a77ab4de26493190280377567d1c/django/db/models/sql/query.py#L235-L236
Now `Col.field` is actually `Expression.field` which is actually an alias
for `.output_field` (not sure why) but in order to allow the special
related field lookup conversion of `SimpleLazyObject` to model instance
(e.g. needed for stuff like `.filter(user=request.user)` where
`request.user` is a `SimpleLazyObject`) it's the `Col.target` that should
be used as `output_field`.
{{{#!diff
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 78c4f47b5b..8ad9d139f9 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -233,7 +233,7 @@ class Query(BaseExpression):
@property
def output_field(self):
if len(self.select) == 1:
- return self.select[0].field
+ return self.select[0].target
elif len(self.annotation_select) == 1:
return
next(iter(self.annotation_select.values())).output_field
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/31420#comment:4>
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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/065.25a2ade6b0a1503a21e41a157d80ca2d%40djangoproject.com.