#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.

Reply via email to