id,summary,reporter,owner,description,type,status,component,version,severity,resolution,keywords,cc,stage,has_patch,needs_docs,needs_tests,needs_better_patch,easy,ui_ux 17439,prefetch_related issues extra queries for optional OneToOneFields,gwahl@…,Aymeric Augustin,"Given these models: {{{#!python class ModelA(models.Model): pass class ModelB(models.Model): a = models.OneToOneField(ModelA, related_name='b') }}} I expect that after doing `ModelA.objects.prefetch_related('b')`, the `b` attribute of all the results can be accessed without causing another query. This is not the case: {{{ >>> from app.models import * >>> a = ModelA.objects.all()[0] SELECT ""app_modela"".""id"" FROM ""app_modela"" LIMIT 1 >>> a.b # should do a query, prefetch_related was not used SELECT ""app_modelb"".""id"", ""app_modelb"".""a_id"" FROM ""app_modelb"" WHERE ""app_modelb"".""a_id"" = 1 Traceback (most recent call last): File """", line 1, in File ""/srv/python-environments/egg/src/django/django/db/models/fields/related.py"", line 255, in __get__ rel_obj = self.get_query_set(instance=instance).get(**params) File ""/srv/python-environments/egg/src/django/django/db/models/query.py"", line 361, in get % self.model._meta.object_name) DoesNotExist: ModelB matching query does not exist. ## it did another query, and raised DoesNotExist, just like expected. >>> a = ModelA.objects.all().prefetch_related('b')[0] SELECT ""app_modela"".""id"" FROM ""app_modela"" LIMIT 1 SELECT ""app_modelb"".""id"", ""app_modelb"".""a_id"" FROM ""app_modelb"" >>> a.b # should not do a query, we already got all the `b`s SELECT ""app_modelb"".""id"", ""app_modelb"".""a_id"" FROM ""app_modelb"" WHERE ""app_modelb"".""a_id"" = 1 Traceback (most recent call last): File """", line 1, in File ""/srv/python-environments/egg/src/django/django/db/models/fields/related.py"", line 255, in __get__ rel_obj = self.get_query_set(instance=instance).get(**params) File ""/srv/python-environments/egg/src/django/django/db/models/query.py"", line 361, in get % self.model._meta.object_name) DoesNotExist: ModelB matching query does not exist. ## Another query was issued even though we know it can not return any results >>> }}} Any possible `b` object was already fetched by `prefetch_related`, but accessing the property causes another query anyway. Note that this is only the case when `a` does not have a `b` object, the extra query does not happen if there was a `b` fetched by `prefetch_related`. ",Bug,closed,"Database layer (models, ORM)",dev,Normal,fixed,,,Ready for checkin,0,0,0,0,0,0