﻿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 ""<console>"", line 1, in <module>
  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 ""<console>"", line 1, in <module>
  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
