#17003: prefetch_related should support foreign keys/one-to-one
-------------------------------------+-------------------------------------
     Reporter:  lukeplant            |                    Owner:  nobody
         Type:  New feature          |                   Status:  new
    Component:  Database layer       |                  Version:  1.3
  (models, ORM)                      |               Resolution:
     Severity:  Normal               |             Triage Stage:  Accepted
     Keywords:                       |      Needs documentation:  0
    Has patch:  0                    |  Patch needs improvement:  0
  Needs tests:  0                    |                    UI/UX:  0
Easy pickings:  0                    |
-------------------------------------+-------------------------------------
Changes (by lukeplant):

 * stage:  Unreviewed => Accepted


Old description:

> Although it is currently billed as providing support for many-to-many or
> the 'many' side of foreign key relationships, there is nothing in the
> name or API which stops prefetch_related providing support for foreign
> key relationships or one-to-one.
>
> Often, select_related will be a better alternative for these
> relationships, since they can be done with a database join. However:
>
> 1. It is possible that in practice that doing a separate query and
> joining in Python is faster.
> 2. There are cases where it may be difficult to arrange for the
> relationships to be included via `select_related()`. For example if you
> do `prefetch_related('many1__single__many2')`, then, although
> prefetch_related will ''traverse'' the 'single' relationship to get to
> 'many2', it could execute many DB queries when it does so.
>
> An ideal solution to this would allow prefetching of things like
> `GenericForeignKey`, and potentially other similar 3rd party constructs.
> For example, someone might have a `CrossDatabaseForeignKey`, which would
> not have referential integrity since the related data is in a different
> database, but provides convenient access on objects, and would benefit
> from being able to do a prefetch for efficient access. (select_related,
> being JOIN based, is clearly out of the picture for this use case). This
> suggests that some API similar to the one created for many-related-
> managers (i.e. existence of a `get_prefetch_query_set()` method) should
> be used.
>
> The primary difference for singly related objects is that we have to
> avoid simply fetching the attribute from the instance, as this will cause
> the descriptor `__get__()` to be called, and the query to be done
> immediately the inefficient way. We can do this by calling `getattr` on
> the class, which will retrieve the descriptor object itself.
>
> For reference, it appears that Ruby on Rails using something like
> `prefetch_related()` for all
> [http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
> eager loading of relationships], and doesn't have an equivalent to
> `select_related()`.

New description:

 Although it is currently billed as providing support for many-to-many or
 the 'many' side of foreign key relationships, there is nothing in the name
 or API which stops prefetch_related providing support for foreign key
 relationships or one-to-one.

 Often, select_related will be a better alternative for these
 relationships, since they can be done with a database join. However:

 1. It is possible that in practice it is better to do a separate query and
 join in Python.
 2. There are cases where it may be difficult to arrange for the
 relationships to be included via `select_related()`. For example if you do
 `prefetch_related('many1__single__many2')`, then, although
 prefetch_related will ''traverse'' the 'single' relationship to get to
 'many2', it could execute many DB queries when it does so.

 An ideal solution to this would allow prefetching of things like
 `GenericForeignKey`, and potentially other similar 3rd party constructs.
 For example, someone might have a `CrossDatabaseForeignKey`, which would
 not have referential integrity since the related data is in a different
 database, but provides convenient access on objects, and would benefit
 from being able to do a prefetch for efficient access. (select_related,
 being JOIN based, is clearly out of the picture for this use case). This
 suggests that some API similar to the one created for many-related-
 managers (i.e. existence of a `get_prefetch_query_set()` method) should be
 used.

 The primary difference for singly related objects is that we have to avoid
 simply fetching the attribute from the instance, as this will cause the
 descriptor `__get__()` to be called, and the query to be done immediately
 the inefficient way. We can do this by calling `getattr` on the class,
 which will retrieve the descriptor object itself.

 For reference, it appears that Ruby on Rails uses something like
 `prefetch_related()` for all
 [http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
 eager loading of relationships], and doesn't have an equivalent to
 `select_related()`.

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/17003#comment:1>
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 post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to