prefetch_related should support foreign keys/one-to-one
|Reported by:||Luke Plant||Owned by:||nobody|
|Component:||Database layer (models, ORM)||Version:||1.3|
|Has patch:||yes||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
Description (last modified by )
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:
- It is possible that in practice it is better to do a separate query and join in Python.
- 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 eager loading of relationships, and doesn't have an equivalent to