#17001: Allow usage of custom querysets in prefetch_related
-------------------------------------+-------------------------------------
     Reporter:  akaariai             |                    Owner:  loic84
         Type:  New feature          |                   Status:  assigned
    Component:  Database layer       |                  Version:  master
  (models, ORM)                      |               Resolution:
     Severity:  Normal               |             Triage Stage:  Accepted
     Keywords:  prefetch_related     |      Needs documentation:  1
    Has patch:  1                    |  Patch needs improvement:  1
  Needs tests:  1                    |                    UI/UX:  0
Easy pickings:  0                    |
-------------------------------------+-------------------------------------

Comment (by loic84):

 As @akaariai pointed out in #comment:24, `kwargs` are not ordered; yet
 ordering matters a fair bit.

 For example my example from the previous comment:

 {{{#!python
     Restaurant.objects.prefetch_related(
         'pizza_list__toppings_list',
          pizza_list=Prefetch('pizza'),
     )
 }}}

 This wouldn't work without some
 [https://github.com/loic/django/compare/prefetch_related#diff-
 5b0dda5eb9a242c15879dc9cd2121379R1652 sorting in the implementation].

 I then found out that `*args` ordering is something
 
[https://github.com/django/django/blob/master/tests/prefetch_related/tests.py#L453
 we actually test for], even though it doesn't seem documented. This
 implicit ordering allows for `@properties` to
 
[https://github.com/django/django/blob/master/tests/prefetch_related/models.py#L177
 masquerade as managers].

 Sorting by lookup like in my patch, would obviously mess that up.

 We could:

 1. Do the sorting based on the lookup path and add an `after` argument to
 the `Prefetch` object, so you could do
 `prefetch_related(Prefetch('primary_house__occupants',
 after='houses__rooms'), 'houses__rooms')`. This would actually be backward
 **incompatible** for whomever already rely on the implicit ordering of
 `*args`, since you need to opt-in for a custom `after`.

 2. Require multiple calls to `prefetch_related()` when ordering matters:
 
`prefetch_related(pizza_list=Prefetch('pizza')).prefetch_related('pizza_list__toppings_list')`.
 IMO this adds yet another construct to an already complicated API.

 3. Go back to having `to_attr` as a `Prefetch` argument rather than a
 `kwarg`, and finally document that ordering of `*args` actually matters.
 This is backward **compatible**, and it also makes for a **cleaner
 implementation**. I was actually on the verge of adding it (undocumented),
 only for the purpose of cleaning up the current implementation.

 For the record, I favor 3) by a big margin.

 Please note that while `prefetch_related('foo__bar__baz', 'foo__bar')`
 and `prefetch_related('foo__bar', 'foo__bar__baz')` were equivalent, it's
 not necessarily true anymore now that we can do
 `prefetch_related(Prefetch('foo__bar', queryset=...), 'foo__bar__baz')`,
 so the actual ordering becomes a more prominent concern than before.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/17001#comment:34>
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 post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/066.d288fe4de33279ed971d465ef9682ff8%40djangoproject.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to