#29545: Nested OuterRef not looking on the right model for the field.
-------------------------------------+-------------------------------------
     Reporter:  Aaron Lisman         |                    Owner:  Simon
                                     |  Charette
         Type:  Bug                  |                   Status:  assigned
    Component:  Database layer       |                  Version:  master
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:  outerref, subquery   |             Triage Stage:  Accepted
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

 * status:  new => assigned
 * owner:  nobody => Simon Charette


Comment:

 This is more of a brain dump than a final resolution but I think I might
 have nailed it down. I thought I'd share how I came with what I believe is
 the solution to share a bit of knowledge about how the ORM resolves
 expressions.

 By breaking the query construction in multiple statements and adding
 breakpoints in `OuterRef.resolve_expression` and
 `ResolvedOuterRef.resolve_expression` I noticed that the latter was being
 called '''after''' the complete query construction when it was being
 executed which should not happen. In short all expressions should be
 resolved to their '''final''' expression at this point and in the case of
 `OuterRef` and `ResolvedOuterRef` they should be `Col` instances.

 I then assumed that something must not be have been esolved properly so I
 added a breakpoint before the `print(qs)` and dug into `qs.query`
 internals. By walking the chain of
 `qs.query.annotations['has_item'].query` I noticed that
 `.where.children[0].lhs` was and `Exist` instance and that its
 `.query.where.children[0].rhs` happened to be a `ResolvedOuterRef`
 instance. I then knew that this was the culprit as it should have been a
 `Col` by this point. I also noticed that the copy of the `Exists` present
 as the `.has_tag` expression had its `.query.where.children[0].rhs`
 correctly resolved to a `Col` so I adjusted the test to replace the
 unresolved reference to the `Col` and got the test passing.


 {{{#!python
 def test_nested_outerref(self):
     number = Number.objects.create(num=5)
     Node.objects.create(num=5)
     nested_query = Node.objects.filter(num=OuterRef(OuterRef('num')))
     nested_exist = Exists(nested_query)
     query = Item.objects.annotate(
         has_tag=nested_exist,
     ).filter(has_tag=True)
     exists = Exists(query)
     qs = Number.objects.annotate(
         has_item=exists
     )
     col =
 
qs.query.annotations['has_item'].query.annotations['has_tag'].query.where.children[0].rhs
 
qs.query.annotations['has_item'].query.where.children[0].lhs.query.where.children[0].rhs
 = col
     print(str(qs.query))
     self.assertEqual(qs.get(), number)
 }}}

 From that point I knew that there was an issue resolving
 `qs.query.annotations['has_item'].query.where.children[0].lhs` and then I
 remembered that `sql.Where.resolve_expression` was performing resolving
 for `.rhs` of lookups but not for `.lhs` which brought me to
 [https://github.com/django/django/compare/master...charettes:ticket-29545
 this still incomplete patch] that happens to solve this issue and pass the
 test suite on SQLite so far.

 I've assigned the ticket to myself as I plan to submit the above branch
 for review in the next days. I wouldn't be surprised if it fixed a other
 issues related to subqueries and `OuterRef`.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29545#comment:7>
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 django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/063.d2282a1bbfe2eb29938c13024f44ab87%40djangoproject.com.

Reply via email to