Loading django/db/models/sql/query.py +4 −1 Original line number Diff line number Diff line Loading @@ -1712,7 +1712,10 @@ class Query(object): certain related models (as opposed to all models, when self.select_related=True). """ if isinstance(self.select_related, bool): field_dict = {} else: field_dict = self.select_related for field in fields: d = field_dict for part in field.split(LOOKUP_SEP): Loading docs/ref/models/querysets.txt +26 −48 Original line number Diff line number Diff line Loading @@ -688,13 +688,12 @@ manager or a ``QuerySet`` and do further filtering on the result. After calling select_related ~~~~~~~~~~~~~~ .. method:: select_related() .. method:: select_related(*fields) Returns a ``QuerySet`` that will automatically "follow" foreign-key relationships, selecting that additional related-object data when it executes its query. This is a performance booster which results in (sometimes much) larger queries but means later use of foreign-key relationships won't require database queries. Returns a ``QuerySet`` that will "follow" foreign-key relationships, selecting additional related-object data when it executes its query. This is a performance booster which results in a single more complex query but means later use of foreign-key relationships won't require database queries. The following examples illustrate the difference between plain lookups and ``select_related()`` lookups. Here's standard lookup:: Loading @@ -708,13 +707,13 @@ The following examples illustrate the difference between plain lookups and And here's ``select_related`` lookup:: # Hits the database. e = Entry.objects.select_related().get(id=5) e = Entry.objects.select_related('blog').get(id=5) # Doesn't hit the database, because e.blog has been prepopulated # in the previous query. b = e.blog ``select_related()`` follows foreign keys as far as possible. If you have the You can follow foreign keys in a similar way to querying them. If you have the following models:: from django.db import models Loading @@ -731,10 +730,11 @@ following models:: # ... author = models.ForeignKey(Person) ...then a call to ``Book.objects.select_related().get(id=4)`` will cache the related ``Person`` *and* the related ``City``:: ...then a call to ``Book.objects.select_related('person', 'person__city').get(id=4)`` will cache the related ``Person`` *and* the related ``City``:: b = Book.objects.select_related().get(id=4) b = Book.objects.select_related('person__city').get(id=4) p = b.author # Doesn't hit the database. c = p.hometown # Doesn't hit the database. Loading @@ -742,45 +742,9 @@ related ``Person`` *and* the related ``City``:: p = b.author # Hits the database. c = p.hometown # Hits the database. Note that, by default, ``select_related()`` does not follow foreign keys that have ``null=True``. Usually, using ``select_related()`` can vastly improve performance because your app can avoid many database calls. However, there are times you are only interested in specific related models, or have deeply nested sets of relationships, and in these cases ``select_related()`` can be optimized by explicitly passing the related field names you are interested in. Only the specified relations will be followed. You can even do this for models that are more than one relation away by separating the field names with double underscores, just as for filters. For example, if you have this model:: class Room(models.Model): # ... building = models.ForeignKey(...) class Group(models.Model): # ... teacher = models.ForeignKey(...) room = models.ForeignKey(Room) subject = models.ForeignKey(...) ...and you only needed to work with the ``room`` and ``subject`` attributes, you could write this:: g = Group.objects.select_related('room', 'subject') This is also valid:: g = Group.objects.select_related('room__building', 'subject') ...and would also pull in the ``building`` relation. You can refer to any :class:`~django.db.models.ForeignKey` or :class:`~django.db.models.OneToOneField` relation in the list of fields passed to ``select_related()``. This includes foreign keys that have ``null=True`` (which are omitted in a no-parameter ``select_related()`` call). passed to ``select_related()``. You can also refer to the reverse direction of a :class:`~django.db.models.OneToOneField` in the list of fields passed to Loading @@ -789,6 +753,13 @@ You can also refer to the reverse direction of a is defined. Instead of specifying the field name, use the :attr:`related_name <django.db.models.ForeignKey.related_name>` for the field on the related object. There may be some situations where you wish to call ``select_related()`` with a lot of related objects, or where you don't know all of the relations. In these cases it is possible to call ``select_related()`` with no arguments. This will follow all non-null foreign keys it can find - nullable foreign keys must be specified. This is not recommended in most cases as it is likely to make the underlying query more complex, and return more data, than is actually needed. .. versionadded:: 1.6 If you need to clear the list of related fields added by past calls of Loading @@ -796,6 +767,13 @@ If you need to clear the list of related fields added by past calls of >>> without_relations = queryset.select_related(None) .. versionchanged:: 1.7 Chaining ``select_related`` calls now works in a similar way to other methods - that is that ``select_related('foo', 'bar')`` is equivalent to ``select_related('foo').select_related('bar')``. Previously the latter would have been equivalent to ``select_related('bar')``. prefetch_related ~~~~~~~~~~~~~~~~ Loading docs/releases/1.7.txt +6 −0 Original line number Diff line number Diff line Loading @@ -533,6 +533,12 @@ Miscellaneous you relied on the default field ordering while having fields defined on both the current class *and* on a parent ``Form``. * :meth:`~django.db.models.query.QuerySet.select_related` now chains in the same way as other similar calls like ``prefetch_related``. That is, ``select_related('foo', 'bar')`` is equivalent to ``select_related('foo').select_related('bar')``. Previously the latter would have been equivalent to ``select_related('bar')``. Features deprecated in 1.7 ========================== Loading tests/select_related/models.py +9 −0 Original line number Diff line number Diff line Loading @@ -66,3 +66,12 @@ class Species(models.Model): genus = models.ForeignKey(Genus) def __str__(self): return self.name # and we'll invent a new thing so we have a model with two foreign keys @python_2_unicode_compatible class HybridSpecies(models.Model): name = models.CharField(max_length=50) parent_1 = models.ForeignKey(Species, related_name='child_1') parent_2 = models.ForeignKey(Species, related_name='child_2') def __str__(self): return self.name tests/select_related/tests.py +10 −1 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.test import TestCase from .models import Domain, Kingdom, Phylum, Klass, Order, Family, Genus, Species from .models import Domain, Kingdom, Phylum, Klass, Order, Family, Genus, Species, HybridSpecies class SelectRelatedTests(TestCase): Loading Loading @@ -144,3 +144,12 @@ class SelectRelatedTests(TestCase): def test_none_clears_list(self): queryset = Species.objects.select_related('genus').select_related(None) self.assertEqual(queryset.query.select_related, False) def test_chaining(self): parent_1, parent_2 = Species.objects.all()[:2] HybridSpecies.objects.create(name='hybrid', parent_1=parent_1, parent_2=parent_2) queryset = HybridSpecies.objects.select_related('parent_1').select_related('parent_2') with self.assertNumQueries(1): obj = queryset[0] self.assertEquals(obj.parent_1, parent_1) self.assertEquals(obj.parent_2, parent_2) Loading
django/db/models/sql/query.py +4 −1 Original line number Diff line number Diff line Loading @@ -1712,7 +1712,10 @@ class Query(object): certain related models (as opposed to all models, when self.select_related=True). """ if isinstance(self.select_related, bool): field_dict = {} else: field_dict = self.select_related for field in fields: d = field_dict for part in field.split(LOOKUP_SEP): Loading
docs/ref/models/querysets.txt +26 −48 Original line number Diff line number Diff line Loading @@ -688,13 +688,12 @@ manager or a ``QuerySet`` and do further filtering on the result. After calling select_related ~~~~~~~~~~~~~~ .. method:: select_related() .. method:: select_related(*fields) Returns a ``QuerySet`` that will automatically "follow" foreign-key relationships, selecting that additional related-object data when it executes its query. This is a performance booster which results in (sometimes much) larger queries but means later use of foreign-key relationships won't require database queries. Returns a ``QuerySet`` that will "follow" foreign-key relationships, selecting additional related-object data when it executes its query. This is a performance booster which results in a single more complex query but means later use of foreign-key relationships won't require database queries. The following examples illustrate the difference between plain lookups and ``select_related()`` lookups. Here's standard lookup:: Loading @@ -708,13 +707,13 @@ The following examples illustrate the difference between plain lookups and And here's ``select_related`` lookup:: # Hits the database. e = Entry.objects.select_related().get(id=5) e = Entry.objects.select_related('blog').get(id=5) # Doesn't hit the database, because e.blog has been prepopulated # in the previous query. b = e.blog ``select_related()`` follows foreign keys as far as possible. If you have the You can follow foreign keys in a similar way to querying them. If you have the following models:: from django.db import models Loading @@ -731,10 +730,11 @@ following models:: # ... author = models.ForeignKey(Person) ...then a call to ``Book.objects.select_related().get(id=4)`` will cache the related ``Person`` *and* the related ``City``:: ...then a call to ``Book.objects.select_related('person', 'person__city').get(id=4)`` will cache the related ``Person`` *and* the related ``City``:: b = Book.objects.select_related().get(id=4) b = Book.objects.select_related('person__city').get(id=4) p = b.author # Doesn't hit the database. c = p.hometown # Doesn't hit the database. Loading @@ -742,45 +742,9 @@ related ``Person`` *and* the related ``City``:: p = b.author # Hits the database. c = p.hometown # Hits the database. Note that, by default, ``select_related()`` does not follow foreign keys that have ``null=True``. Usually, using ``select_related()`` can vastly improve performance because your app can avoid many database calls. However, there are times you are only interested in specific related models, or have deeply nested sets of relationships, and in these cases ``select_related()`` can be optimized by explicitly passing the related field names you are interested in. Only the specified relations will be followed. You can even do this for models that are more than one relation away by separating the field names with double underscores, just as for filters. For example, if you have this model:: class Room(models.Model): # ... building = models.ForeignKey(...) class Group(models.Model): # ... teacher = models.ForeignKey(...) room = models.ForeignKey(Room) subject = models.ForeignKey(...) ...and you only needed to work with the ``room`` and ``subject`` attributes, you could write this:: g = Group.objects.select_related('room', 'subject') This is also valid:: g = Group.objects.select_related('room__building', 'subject') ...and would also pull in the ``building`` relation. You can refer to any :class:`~django.db.models.ForeignKey` or :class:`~django.db.models.OneToOneField` relation in the list of fields passed to ``select_related()``. This includes foreign keys that have ``null=True`` (which are omitted in a no-parameter ``select_related()`` call). passed to ``select_related()``. You can also refer to the reverse direction of a :class:`~django.db.models.OneToOneField` in the list of fields passed to Loading @@ -789,6 +753,13 @@ You can also refer to the reverse direction of a is defined. Instead of specifying the field name, use the :attr:`related_name <django.db.models.ForeignKey.related_name>` for the field on the related object. There may be some situations where you wish to call ``select_related()`` with a lot of related objects, or where you don't know all of the relations. In these cases it is possible to call ``select_related()`` with no arguments. This will follow all non-null foreign keys it can find - nullable foreign keys must be specified. This is not recommended in most cases as it is likely to make the underlying query more complex, and return more data, than is actually needed. .. versionadded:: 1.6 If you need to clear the list of related fields added by past calls of Loading @@ -796,6 +767,13 @@ If you need to clear the list of related fields added by past calls of >>> without_relations = queryset.select_related(None) .. versionchanged:: 1.7 Chaining ``select_related`` calls now works in a similar way to other methods - that is that ``select_related('foo', 'bar')`` is equivalent to ``select_related('foo').select_related('bar')``. Previously the latter would have been equivalent to ``select_related('bar')``. prefetch_related ~~~~~~~~~~~~~~~~ Loading
docs/releases/1.7.txt +6 −0 Original line number Diff line number Diff line Loading @@ -533,6 +533,12 @@ Miscellaneous you relied on the default field ordering while having fields defined on both the current class *and* on a parent ``Form``. * :meth:`~django.db.models.query.QuerySet.select_related` now chains in the same way as other similar calls like ``prefetch_related``. That is, ``select_related('foo', 'bar')`` is equivalent to ``select_related('foo').select_related('bar')``. Previously the latter would have been equivalent to ``select_related('bar')``. Features deprecated in 1.7 ========================== Loading
tests/select_related/models.py +9 −0 Original line number Diff line number Diff line Loading @@ -66,3 +66,12 @@ class Species(models.Model): genus = models.ForeignKey(Genus) def __str__(self): return self.name # and we'll invent a new thing so we have a model with two foreign keys @python_2_unicode_compatible class HybridSpecies(models.Model): name = models.CharField(max_length=50) parent_1 = models.ForeignKey(Species, related_name='child_1') parent_2 = models.ForeignKey(Species, related_name='child_2') def __str__(self): return self.name
tests/select_related/tests.py +10 −1 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.test import TestCase from .models import Domain, Kingdom, Phylum, Klass, Order, Family, Genus, Species from .models import Domain, Kingdom, Phylum, Klass, Order, Family, Genus, Species, HybridSpecies class SelectRelatedTests(TestCase): Loading Loading @@ -144,3 +144,12 @@ class SelectRelatedTests(TestCase): def test_none_clears_list(self): queryset = Species.objects.select_related('genus').select_related(None) self.assertEqual(queryset.query.select_related, False) def test_chaining(self): parent_1, parent_2 = Species.objects.all()[:2] HybridSpecies.objects.create(name='hybrid', parent_1=parent_1, parent_2=parent_2) queryset = HybridSpecies.objects.select_related('parent_1').select_related('parent_2') with self.assertNumQueries(1): obj = queryset[0] self.assertEquals(obj.parent_1, parent_1) self.assertEquals(obj.parent_2, parent_2)