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